1*e4b0a90eSBrooks Davis /*- 2*e4b0a90eSBrooks Davis * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*e4b0a90eSBrooks Davis * 4*e4b0a90eSBrooks Davis * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5*e4b0a90eSBrooks Davis * All rights reserved. 6*e4b0a90eSBrooks Davis * 7*e4b0a90eSBrooks Davis * Redistribution and use in source and binary forms, with or without 8*e4b0a90eSBrooks Davis * modification, are permitted provided that the following conditions 9*e4b0a90eSBrooks Davis * are met: 10*e4b0a90eSBrooks Davis * 1. Redistributions of source code must retain the above copyright 11*e4b0a90eSBrooks Davis * notice, this list of conditions and the following disclaimer. 12*e4b0a90eSBrooks Davis * 2. Redistributions in binary form must reproduce the above copyright 13*e4b0a90eSBrooks Davis * notice, this list of conditions and the following disclaimer in the 14*e4b0a90eSBrooks Davis * documentation and/or other materials provided with the distribution. 15*e4b0a90eSBrooks Davis * 16*e4b0a90eSBrooks Davis * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17*e4b0a90eSBrooks Davis * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*e4b0a90eSBrooks Davis * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*e4b0a90eSBrooks Davis * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20*e4b0a90eSBrooks Davis * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*e4b0a90eSBrooks Davis * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*e4b0a90eSBrooks Davis * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*e4b0a90eSBrooks Davis * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*e4b0a90eSBrooks Davis * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*e4b0a90eSBrooks Davis * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*e4b0a90eSBrooks Davis * SUCH DAMAGE. 27*e4b0a90eSBrooks Davis */ 28*e4b0a90eSBrooks Davis 29*e4b0a90eSBrooks Davis #include <sys/cdefs.h> 30*e4b0a90eSBrooks Davis __FBSDID("$FreeBSD$"); 31*e4b0a90eSBrooks Davis 32*e4b0a90eSBrooks Davis #include <sys/types.h> 33*e4b0a90eSBrooks Davis #include <errno.h> 34*e4b0a90eSBrooks Davis #include <paths.h> 35*e4b0a90eSBrooks Davis #include <stdio.h> 36*e4b0a90eSBrooks Davis #include <stdlib.h> 37*e4b0a90eSBrooks Davis #include <stdint.h> 38*e4b0a90eSBrooks Davis #include <string.h> 39*e4b0a90eSBrooks Davis #include <strings.h> 40*e4b0a90eSBrooks Davis #include <assert.h> 41*e4b0a90eSBrooks Davis #include <libgeom.h> 42*e4b0a90eSBrooks Davis #include <geom/journal/g_journal.h> 43*e4b0a90eSBrooks Davis #include <core/geom.h> 44*e4b0a90eSBrooks Davis #include <misc/subr.h> 45*e4b0a90eSBrooks Davis 46*e4b0a90eSBrooks Davis #include "geom_journal.h" 47*e4b0a90eSBrooks Davis 48*e4b0a90eSBrooks Davis 49*e4b0a90eSBrooks Davis uint32_t lib_version = G_LIB_VERSION; 50*e4b0a90eSBrooks Davis uint32_t version = G_JOURNAL_VERSION; 51*e4b0a90eSBrooks Davis 52*e4b0a90eSBrooks Davis static void journal_main(struct gctl_req *req, unsigned flags); 53*e4b0a90eSBrooks Davis static void journal_clear(struct gctl_req *req); 54*e4b0a90eSBrooks Davis static void journal_dump(struct gctl_req *req); 55*e4b0a90eSBrooks Davis static void journal_label(struct gctl_req *req); 56*e4b0a90eSBrooks Davis 57*e4b0a90eSBrooks Davis struct g_command class_commands[] = { 58*e4b0a90eSBrooks Davis { "clear", G_FLAG_VERBOSE, journal_main, G_NULL_OPTS, 59*e4b0a90eSBrooks Davis "[-v] prov ..." 60*e4b0a90eSBrooks Davis }, 61*e4b0a90eSBrooks Davis { "dump", 0, journal_main, G_NULL_OPTS, 62*e4b0a90eSBrooks Davis "prov ..." 63*e4b0a90eSBrooks Davis }, 64*e4b0a90eSBrooks Davis { "label", G_FLAG_VERBOSE, journal_main, 65*e4b0a90eSBrooks Davis { 66*e4b0a90eSBrooks Davis { 'c', "checksum", NULL, G_TYPE_BOOL }, 67*e4b0a90eSBrooks Davis { 'f', "force", NULL, G_TYPE_BOOL }, 68*e4b0a90eSBrooks Davis { 'h', "hardcode", NULL, G_TYPE_BOOL }, 69*e4b0a90eSBrooks Davis { 's', "jsize", "-1", G_TYPE_NUMBER }, 70*e4b0a90eSBrooks Davis G_OPT_SENTINEL 71*e4b0a90eSBrooks Davis }, 72*e4b0a90eSBrooks Davis "[-cfhv] [-s jsize] dataprov [jprov]" 73*e4b0a90eSBrooks Davis }, 74*e4b0a90eSBrooks Davis { "stop", G_FLAG_VERBOSE, NULL, 75*e4b0a90eSBrooks Davis { 76*e4b0a90eSBrooks Davis { 'f', "force", NULL, G_TYPE_BOOL }, 77*e4b0a90eSBrooks Davis G_OPT_SENTINEL 78*e4b0a90eSBrooks Davis }, 79*e4b0a90eSBrooks Davis "[-fv] name ..." 80*e4b0a90eSBrooks Davis }, 81*e4b0a90eSBrooks Davis { "sync", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, 82*e4b0a90eSBrooks Davis "[-v]" 83*e4b0a90eSBrooks Davis }, 84*e4b0a90eSBrooks Davis G_CMD_SENTINEL 85*e4b0a90eSBrooks Davis }; 86*e4b0a90eSBrooks Davis 87*e4b0a90eSBrooks Davis static int verbose = 0; 88*e4b0a90eSBrooks Davis 89*e4b0a90eSBrooks Davis static void 90*e4b0a90eSBrooks Davis journal_main(struct gctl_req *req, unsigned flags) 91*e4b0a90eSBrooks Davis { 92*e4b0a90eSBrooks Davis const char *name; 93*e4b0a90eSBrooks Davis 94*e4b0a90eSBrooks Davis if ((flags & G_FLAG_VERBOSE) != 0) 95*e4b0a90eSBrooks Davis verbose = 1; 96*e4b0a90eSBrooks Davis 97*e4b0a90eSBrooks Davis name = gctl_get_ascii(req, "verb"); 98*e4b0a90eSBrooks Davis if (name == NULL) { 99*e4b0a90eSBrooks Davis gctl_error(req, "No '%s' argument.", "verb"); 100*e4b0a90eSBrooks Davis return; 101*e4b0a90eSBrooks Davis } 102*e4b0a90eSBrooks Davis if (strcmp(name, "label") == 0) 103*e4b0a90eSBrooks Davis journal_label(req); 104*e4b0a90eSBrooks Davis else if (strcmp(name, "clear") == 0) 105*e4b0a90eSBrooks Davis journal_clear(req); 106*e4b0a90eSBrooks Davis else if (strcmp(name, "dump") == 0) 107*e4b0a90eSBrooks Davis journal_dump(req); 108*e4b0a90eSBrooks Davis else 109*e4b0a90eSBrooks Davis gctl_error(req, "Unknown command: %s.", name); 110*e4b0a90eSBrooks Davis } 111*e4b0a90eSBrooks Davis 112*e4b0a90eSBrooks Davis static int 113*e4b0a90eSBrooks Davis g_journal_fs_exists(const char *prov) 114*e4b0a90eSBrooks Davis { 115*e4b0a90eSBrooks Davis 116*e4b0a90eSBrooks Davis if (g_journal_ufs_exists(prov)) 117*e4b0a90eSBrooks Davis return (1); 118*e4b0a90eSBrooks Davis #if 0 119*e4b0a90eSBrooks Davis if (g_journal_otherfs_exists(prov)) 120*e4b0a90eSBrooks Davis return (1); 121*e4b0a90eSBrooks Davis #endif 122*e4b0a90eSBrooks Davis return (0); 123*e4b0a90eSBrooks Davis } 124*e4b0a90eSBrooks Davis 125*e4b0a90eSBrooks Davis static int 126*e4b0a90eSBrooks Davis g_journal_fs_using_last_sector(const char *prov) 127*e4b0a90eSBrooks Davis { 128*e4b0a90eSBrooks Davis 129*e4b0a90eSBrooks Davis if (g_journal_ufs_using_last_sector(prov)) 130*e4b0a90eSBrooks Davis return (1); 131*e4b0a90eSBrooks Davis #if 0 132*e4b0a90eSBrooks Davis if (g_journal_otherfs_using_last_sector(prov)) 133*e4b0a90eSBrooks Davis return (1); 134*e4b0a90eSBrooks Davis #endif 135*e4b0a90eSBrooks Davis return (0); 136*e4b0a90eSBrooks Davis } 137*e4b0a90eSBrooks Davis 138*e4b0a90eSBrooks Davis static void 139*e4b0a90eSBrooks Davis journal_label(struct gctl_req *req) 140*e4b0a90eSBrooks Davis { 141*e4b0a90eSBrooks Davis struct g_journal_metadata md; 142*e4b0a90eSBrooks Davis const char *data, *journal, *str; 143*e4b0a90eSBrooks Davis u_char sector[512]; 144*e4b0a90eSBrooks Davis intmax_t jsize, msize, ssize; 145*e4b0a90eSBrooks Davis int error, force, i, nargs, checksum, hardcode; 146*e4b0a90eSBrooks Davis 147*e4b0a90eSBrooks Davis bzero(sector, sizeof(sector)); 148*e4b0a90eSBrooks Davis nargs = gctl_get_int(req, "nargs"); 149*e4b0a90eSBrooks Davis str = NULL; /* gcc */ 150*e4b0a90eSBrooks Davis 151*e4b0a90eSBrooks Davis strlcpy(md.md_magic, G_JOURNAL_MAGIC, sizeof(md.md_magic)); 152*e4b0a90eSBrooks Davis md.md_version = G_JOURNAL_VERSION; 153*e4b0a90eSBrooks Davis md.md_id = arc4random(); 154*e4b0a90eSBrooks Davis md.md_joffset = 0; 155*e4b0a90eSBrooks Davis md.md_jid = 0; 156*e4b0a90eSBrooks Davis md.md_flags = GJ_FLAG_CLEAN; 157*e4b0a90eSBrooks Davis checksum = gctl_get_int(req, "checksum"); 158*e4b0a90eSBrooks Davis if (checksum) 159*e4b0a90eSBrooks Davis md.md_flags |= GJ_FLAG_CHECKSUM; 160*e4b0a90eSBrooks Davis force = gctl_get_int(req, "force"); 161*e4b0a90eSBrooks Davis hardcode = gctl_get_int(req, "hardcode"); 162*e4b0a90eSBrooks Davis 163*e4b0a90eSBrooks Davis if (nargs != 1 && nargs != 2) { 164*e4b0a90eSBrooks Davis gctl_error(req, "Invalid number of arguments."); 165*e4b0a90eSBrooks Davis return; 166*e4b0a90eSBrooks Davis } 167*e4b0a90eSBrooks Davis 168*e4b0a90eSBrooks Davis /* Verify the given providers. */ 169*e4b0a90eSBrooks Davis for (i = 0; i < nargs; i++) { 170*e4b0a90eSBrooks Davis str = gctl_get_ascii(req, "arg%d", i); 171*e4b0a90eSBrooks Davis if (g_get_mediasize(str) == 0) { 172*e4b0a90eSBrooks Davis gctl_error(req, "Invalid provider %s.", str); 173*e4b0a90eSBrooks Davis return; 174*e4b0a90eSBrooks Davis } 175*e4b0a90eSBrooks Davis } 176*e4b0a90eSBrooks Davis 177*e4b0a90eSBrooks Davis data = gctl_get_ascii(req, "arg0"); 178*e4b0a90eSBrooks Davis jsize = gctl_get_intmax(req, "jsize"); 179*e4b0a90eSBrooks Davis journal = NULL; 180*e4b0a90eSBrooks Davis switch (nargs) { 181*e4b0a90eSBrooks Davis case 1: 182*e4b0a90eSBrooks Davis if (!force && g_journal_fs_exists(data)) { 183*e4b0a90eSBrooks Davis gctl_error(req, "File system exists on %s and this " 184*e4b0a90eSBrooks Davis "operation would destroy it.\nUse -f if you " 185*e4b0a90eSBrooks Davis "really want to do it.", data); 186*e4b0a90eSBrooks Davis return; 187*e4b0a90eSBrooks Davis } 188*e4b0a90eSBrooks Davis journal = data; 189*e4b0a90eSBrooks Davis msize = g_get_mediasize(data); 190*e4b0a90eSBrooks Davis ssize = g_get_sectorsize(data); 191*e4b0a90eSBrooks Davis if (jsize == -1) { 192*e4b0a90eSBrooks Davis /* 193*e4b0a90eSBrooks Davis * No journal size specified. 1GB should be safe 194*e4b0a90eSBrooks Davis * default. 195*e4b0a90eSBrooks Davis */ 196*e4b0a90eSBrooks Davis jsize = 1073741824ULL; 197*e4b0a90eSBrooks Davis } else { 198*e4b0a90eSBrooks Davis if (jsize < 104857600) { 199*e4b0a90eSBrooks Davis gctl_error(req, "Journal too small."); 200*e4b0a90eSBrooks Davis return; 201*e4b0a90eSBrooks Davis } 202*e4b0a90eSBrooks Davis if ((jsize % ssize) != 0) { 203*e4b0a90eSBrooks Davis gctl_error(req, "Invalid journal size."); 204*e4b0a90eSBrooks Davis return; 205*e4b0a90eSBrooks Davis } 206*e4b0a90eSBrooks Davis } 207*e4b0a90eSBrooks Davis if (jsize + ssize >= msize) { 208*e4b0a90eSBrooks Davis gctl_error(req, "Provider too small for journalling. " 209*e4b0a90eSBrooks Davis "You can try smaller jsize (default is %jd).", 210*e4b0a90eSBrooks Davis jsize); 211*e4b0a90eSBrooks Davis return; 212*e4b0a90eSBrooks Davis } 213*e4b0a90eSBrooks Davis md.md_jstart = msize - ssize - jsize; 214*e4b0a90eSBrooks Davis md.md_jend = msize - ssize; 215*e4b0a90eSBrooks Davis break; 216*e4b0a90eSBrooks Davis case 2: 217*e4b0a90eSBrooks Davis if (!force && g_journal_fs_using_last_sector(data)) { 218*e4b0a90eSBrooks Davis gctl_error(req, "File system on %s is using the last " 219*e4b0a90eSBrooks Davis "sector and this operation is going to overwrite " 220*e4b0a90eSBrooks Davis "it. Use -f if you really want to do it.", data); 221*e4b0a90eSBrooks Davis return; 222*e4b0a90eSBrooks Davis } 223*e4b0a90eSBrooks Davis journal = gctl_get_ascii(req, "arg1"); 224*e4b0a90eSBrooks Davis if (jsize != -1) { 225*e4b0a90eSBrooks Davis gctl_error(req, "jsize argument is valid only for " 226*e4b0a90eSBrooks Davis "all-in-one configuration."); 227*e4b0a90eSBrooks Davis return; 228*e4b0a90eSBrooks Davis } 229*e4b0a90eSBrooks Davis msize = g_get_mediasize(journal); 230*e4b0a90eSBrooks Davis ssize = g_get_sectorsize(journal); 231*e4b0a90eSBrooks Davis md.md_jstart = 0; 232*e4b0a90eSBrooks Davis md.md_jend = msize - ssize; 233*e4b0a90eSBrooks Davis break; 234*e4b0a90eSBrooks Davis } 235*e4b0a90eSBrooks Davis 236*e4b0a90eSBrooks Davis if (g_get_sectorsize(data) != g_get_sectorsize(journal)) { 237*e4b0a90eSBrooks Davis gctl_error(req, "Not equal sector sizes."); 238*e4b0a90eSBrooks Davis return; 239*e4b0a90eSBrooks Davis } 240*e4b0a90eSBrooks Davis 241*e4b0a90eSBrooks Davis /* 242*e4b0a90eSBrooks Davis * Clear last sector first, to spoil all components if device exists. 243*e4b0a90eSBrooks Davis */ 244*e4b0a90eSBrooks Davis for (i = 0; i < nargs; i++) { 245*e4b0a90eSBrooks Davis str = gctl_get_ascii(req, "arg%d", i); 246*e4b0a90eSBrooks Davis error = g_metadata_clear(str, NULL); 247*e4b0a90eSBrooks Davis if (error != 0) { 248*e4b0a90eSBrooks Davis gctl_error(req, "Cannot clear metadata on %s: %s.", str, 249*e4b0a90eSBrooks Davis strerror(error)); 250*e4b0a90eSBrooks Davis return; 251*e4b0a90eSBrooks Davis } 252*e4b0a90eSBrooks Davis } 253*e4b0a90eSBrooks Davis 254*e4b0a90eSBrooks Davis /* 255*e4b0a90eSBrooks Davis * Ok, store metadata. 256*e4b0a90eSBrooks Davis */ 257*e4b0a90eSBrooks Davis for (i = 0; i < nargs; i++) { 258*e4b0a90eSBrooks Davis switch (i) { 259*e4b0a90eSBrooks Davis case 0: 260*e4b0a90eSBrooks Davis str = data; 261*e4b0a90eSBrooks Davis md.md_type = GJ_TYPE_DATA; 262*e4b0a90eSBrooks Davis if (nargs == 1) 263*e4b0a90eSBrooks Davis md.md_type |= GJ_TYPE_JOURNAL; 264*e4b0a90eSBrooks Davis break; 265*e4b0a90eSBrooks Davis case 1: 266*e4b0a90eSBrooks Davis str = journal; 267*e4b0a90eSBrooks Davis md.md_type = GJ_TYPE_JOURNAL; 268*e4b0a90eSBrooks Davis break; 269*e4b0a90eSBrooks Davis } 270*e4b0a90eSBrooks Davis md.md_provsize = g_get_mediasize(str); 271*e4b0a90eSBrooks Davis assert(md.md_provsize != 0); 272*e4b0a90eSBrooks Davis if (!hardcode) 273*e4b0a90eSBrooks Davis bzero(md.md_provider, sizeof(md.md_provider)); 274*e4b0a90eSBrooks Davis else { 275*e4b0a90eSBrooks Davis if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 276*e4b0a90eSBrooks Davis str += sizeof(_PATH_DEV) - 1; 277*e4b0a90eSBrooks Davis strlcpy(md.md_provider, str, sizeof(md.md_provider)); 278*e4b0a90eSBrooks Davis } 279*e4b0a90eSBrooks Davis journal_metadata_encode(&md, sector); 280*e4b0a90eSBrooks Davis error = g_metadata_store(str, sector, sizeof(sector)); 281*e4b0a90eSBrooks Davis if (error != 0) { 282*e4b0a90eSBrooks Davis fprintf(stderr, "Cannot store metadata on %s: %s.\n", 283*e4b0a90eSBrooks Davis str, strerror(error)); 284*e4b0a90eSBrooks Davis gctl_error(req, "Not fully done."); 285*e4b0a90eSBrooks Davis continue; 286*e4b0a90eSBrooks Davis } 287*e4b0a90eSBrooks Davis if (verbose) 288*e4b0a90eSBrooks Davis printf("Metadata value stored on %s.\n", str); 289*e4b0a90eSBrooks Davis } 290*e4b0a90eSBrooks Davis } 291*e4b0a90eSBrooks Davis 292*e4b0a90eSBrooks Davis static void 293*e4b0a90eSBrooks Davis journal_clear(struct gctl_req *req) 294*e4b0a90eSBrooks Davis { 295*e4b0a90eSBrooks Davis const char *name; 296*e4b0a90eSBrooks Davis int error, i, nargs; 297*e4b0a90eSBrooks Davis 298*e4b0a90eSBrooks Davis nargs = gctl_get_int(req, "nargs"); 299*e4b0a90eSBrooks Davis if (nargs < 1) { 300*e4b0a90eSBrooks Davis gctl_error(req, "Too few arguments."); 301*e4b0a90eSBrooks Davis return; 302*e4b0a90eSBrooks Davis } 303*e4b0a90eSBrooks Davis 304*e4b0a90eSBrooks Davis for (i = 0; i < nargs; i++) { 305*e4b0a90eSBrooks Davis name = gctl_get_ascii(req, "arg%d", i); 306*e4b0a90eSBrooks Davis error = g_metadata_clear(name, G_JOURNAL_MAGIC); 307*e4b0a90eSBrooks Davis if (error != 0) { 308*e4b0a90eSBrooks Davis fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 309*e4b0a90eSBrooks Davis name, strerror(error)); 310*e4b0a90eSBrooks Davis gctl_error(req, "Not fully done."); 311*e4b0a90eSBrooks Davis continue; 312*e4b0a90eSBrooks Davis } 313*e4b0a90eSBrooks Davis if (verbose) 314*e4b0a90eSBrooks Davis printf("Metadata cleared on %s.\n", name); 315*e4b0a90eSBrooks Davis } 316*e4b0a90eSBrooks Davis } 317*e4b0a90eSBrooks Davis 318*e4b0a90eSBrooks Davis static void 319*e4b0a90eSBrooks Davis journal_dump(struct gctl_req *req) 320*e4b0a90eSBrooks Davis { 321*e4b0a90eSBrooks Davis struct g_journal_metadata md, tmpmd; 322*e4b0a90eSBrooks Davis const char *name; 323*e4b0a90eSBrooks Davis int error, i, nargs; 324*e4b0a90eSBrooks Davis 325*e4b0a90eSBrooks Davis nargs = gctl_get_int(req, "nargs"); 326*e4b0a90eSBrooks Davis if (nargs < 1) { 327*e4b0a90eSBrooks Davis gctl_error(req, "Too few arguments."); 328*e4b0a90eSBrooks Davis return; 329*e4b0a90eSBrooks Davis } 330*e4b0a90eSBrooks Davis 331*e4b0a90eSBrooks Davis for (i = 0; i < nargs; i++) { 332*e4b0a90eSBrooks Davis name = gctl_get_ascii(req, "arg%d", i); 333*e4b0a90eSBrooks Davis error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 334*e4b0a90eSBrooks Davis G_JOURNAL_MAGIC); 335*e4b0a90eSBrooks Davis if (error != 0) { 336*e4b0a90eSBrooks Davis fprintf(stderr, "Cannot read metadata from %s: %s.\n", 337*e4b0a90eSBrooks Davis name, strerror(error)); 338*e4b0a90eSBrooks Davis gctl_error(req, "Not fully done."); 339*e4b0a90eSBrooks Davis continue; 340*e4b0a90eSBrooks Davis } 341*e4b0a90eSBrooks Davis if (journal_metadata_decode((u_char *)&tmpmd, &md) != 0) { 342*e4b0a90eSBrooks Davis fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 343*e4b0a90eSBrooks Davis name); 344*e4b0a90eSBrooks Davis gctl_error(req, "Not fully done."); 345*e4b0a90eSBrooks Davis continue; 346*e4b0a90eSBrooks Davis } 347*e4b0a90eSBrooks Davis printf("Metadata on %s:\n", name); 348*e4b0a90eSBrooks Davis journal_metadata_dump(&md); 349*e4b0a90eSBrooks Davis printf("\n"); 350*e4b0a90eSBrooks Davis } 351*e4b0a90eSBrooks Davis } 352