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