1163838Spjd/*- 2163838Spjd * Copyright (c) 2005-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3163838Spjd * All rights reserved. 4163838Spjd * 5163838Spjd * Redistribution and use in source and binary forms, with or without 6163838Spjd * modification, are permitted provided that the following conditions 7163838Spjd * are met: 8163838Spjd * 1. Redistributions of source code must retain the above copyright 9163838Spjd * notice, this list of conditions and the following disclaimer. 10163838Spjd * 2. Redistributions in binary form must reproduce the above copyright 11163838Spjd * notice, this list of conditions and the following disclaimer in the 12163838Spjd * documentation and/or other materials provided with the distribution. 13163838Spjd * 14163838Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15163838Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16163838Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17163838Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18163838Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19163838Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20163838Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21163838Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22163838Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23163838Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24163838Spjd * SUCH DAMAGE. 25163838Spjd */ 26163838Spjd 27163838Spjd#include <sys/cdefs.h> 28163838Spjd__FBSDID("$FreeBSD: stable/10/sbin/geom/class/journal/geom_journal.c 330737 2018-03-10 04:17:01Z asomers $"); 29163838Spjd 30163838Spjd#include <sys/types.h> 31163838Spjd#include <errno.h> 32163838Spjd#include <paths.h> 33163838Spjd#include <stdio.h> 34163838Spjd#include <stdlib.h> 35163838Spjd#include <stdint.h> 36163838Spjd#include <string.h> 37163838Spjd#include <strings.h> 38163838Spjd#include <assert.h> 39163838Spjd#include <libgeom.h> 40163838Spjd#include <geom/journal/g_journal.h> 41163838Spjd#include <core/geom.h> 42163838Spjd#include <misc/subr.h> 43163838Spjd 44163838Spjd#include "geom_journal.h" 45163838Spjd 46163838Spjd 47163838Spjduint32_t lib_version = G_LIB_VERSION; 48163838Spjduint32_t version = G_JOURNAL_VERSION; 49163838Spjd 50163838Spjdstatic void journal_main(struct gctl_req *req, unsigned flags); 51163838Spjdstatic void journal_clear(struct gctl_req *req); 52163838Spjdstatic void journal_dump(struct gctl_req *req); 53163838Spjdstatic void journal_label(struct gctl_req *req); 54163838Spjd 55163838Spjdstruct g_command class_commands[] = { 56212554Spjd { "clear", G_FLAG_VERBOSE, journal_main, G_NULL_OPTS, 57163838Spjd "[-v] prov ..." 58163838Spjd }, 59212554Spjd { "dump", 0, journal_main, G_NULL_OPTS, 60163838Spjd "prov ..." 61163838Spjd }, 62163838Spjd { "label", G_FLAG_VERBOSE, journal_main, 63163838Spjd { 64163838Spjd { 'c', "checksum", NULL, G_TYPE_BOOL }, 65163838Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 66163838Spjd { 'h', "hardcode", NULL, G_TYPE_BOOL }, 67212554Spjd { 's', "jsize", "-1", G_TYPE_NUMBER }, 68163838Spjd G_OPT_SENTINEL 69163838Spjd }, 70212554Spjd "[-cfhv] [-s jsize] dataprov [jprov]" 71163838Spjd }, 72163838Spjd { "stop", G_FLAG_VERBOSE, NULL, 73163838Spjd { 74163838Spjd { 'f', "force", NULL, G_TYPE_BOOL }, 75163838Spjd G_OPT_SENTINEL 76163838Spjd }, 77212554Spjd "[-fv] name ..." 78163838Spjd }, 79212554Spjd { "sync", G_FLAG_VERBOSE, NULL, G_NULL_OPTS, 80163838Spjd "[-v]" 81163838Spjd }, 82163838Spjd G_CMD_SENTINEL 83163838Spjd}; 84163838Spjd 85163838Spjdstatic int verbose = 0; 86163838Spjd 87163838Spjdstatic void 88163838Spjdjournal_main(struct gctl_req *req, unsigned flags) 89163838Spjd{ 90163838Spjd const char *name; 91163838Spjd 92163838Spjd if ((flags & G_FLAG_VERBOSE) != 0) 93163838Spjd verbose = 1; 94163838Spjd 95163838Spjd name = gctl_get_ascii(req, "verb"); 96163838Spjd if (name == NULL) { 97163838Spjd gctl_error(req, "No '%s' argument.", "verb"); 98163838Spjd return; 99163838Spjd } 100163838Spjd if (strcmp(name, "label") == 0) 101163838Spjd journal_label(req); 102163838Spjd else if (strcmp(name, "clear") == 0) 103163838Spjd journal_clear(req); 104163838Spjd else if (strcmp(name, "dump") == 0) 105163838Spjd journal_dump(req); 106163838Spjd else 107163838Spjd gctl_error(req, "Unknown command: %s.", name); 108163838Spjd} 109163838Spjd 110163838Spjdstatic int 111163838Spjdg_journal_fs_exists(const char *prov) 112163838Spjd{ 113163838Spjd 114163838Spjd if (g_journal_ufs_exists(prov)) 115163838Spjd return (1); 116163838Spjd#if 0 117163838Spjd if (g_journal_otherfs_exists(prov)) 118163838Spjd return (1); 119163838Spjd#endif 120163838Spjd return (0); 121163838Spjd} 122163838Spjd 123163838Spjdstatic int 124163838Spjdg_journal_fs_using_last_sector(const char *prov) 125163838Spjd{ 126163838Spjd 127163838Spjd if (g_journal_ufs_using_last_sector(prov)) 128163838Spjd return (1); 129163838Spjd#if 0 130163838Spjd if (g_journal_otherfs_using_last_sector(prov)) 131163838Spjd return (1); 132163838Spjd#endif 133163838Spjd return (0); 134163838Spjd} 135163838Spjd 136163838Spjdstatic void 137163838Spjdjournal_label(struct gctl_req *req) 138163838Spjd{ 139163838Spjd struct g_journal_metadata md; 140163838Spjd const char *data, *journal, *str; 141163838Spjd u_char sector[512]; 142163838Spjd intmax_t jsize, msize, ssize; 143163838Spjd int error, force, i, nargs, checksum, hardcode; 144163838Spjd 145330737Sasomers bzero(sector, sizeof(sector)); 146163838Spjd nargs = gctl_get_int(req, "nargs"); 147163864Spjd str = NULL; /* gcc */ 148163838Spjd 149163838Spjd strlcpy(md.md_magic, G_JOURNAL_MAGIC, sizeof(md.md_magic)); 150163838Spjd md.md_version = G_JOURNAL_VERSION; 151163838Spjd md.md_id = arc4random(); 152163838Spjd md.md_joffset = 0; 153163838Spjd md.md_jid = 0; 154163838Spjd md.md_flags = GJ_FLAG_CLEAN; 155163838Spjd checksum = gctl_get_int(req, "checksum"); 156163838Spjd if (checksum) 157163838Spjd md.md_flags |= GJ_FLAG_CHECKSUM; 158163838Spjd force = gctl_get_int(req, "force"); 159163838Spjd hardcode = gctl_get_int(req, "hardcode"); 160163838Spjd 161163838Spjd if (nargs != 1 && nargs != 2) { 162163838Spjd gctl_error(req, "Invalid number of arguments."); 163163838Spjd return; 164163838Spjd } 165163838Spjd 166163838Spjd /* Verify the given providers. */ 167163838Spjd for (i = 0; i < nargs; i++) { 168163838Spjd str = gctl_get_ascii(req, "arg%d", i); 169163838Spjd if (g_get_mediasize(str) == 0) { 170163838Spjd gctl_error(req, "Invalid provider %s.", str); 171163838Spjd return; 172163838Spjd } 173163838Spjd } 174163838Spjd 175163838Spjd data = gctl_get_ascii(req, "arg0"); 176163838Spjd jsize = gctl_get_intmax(req, "jsize"); 177163838Spjd journal = NULL; 178163838Spjd switch (nargs) { 179163838Spjd case 1: 180163838Spjd if (!force && g_journal_fs_exists(data)) { 181163838Spjd gctl_error(req, "File system exists on %s and this " 182168304Spjd "operation would destroy it.\nUse -f if you " 183163838Spjd "really want to do it.", data); 184163838Spjd return; 185163838Spjd } 186163838Spjd journal = data; 187168304Spjd msize = g_get_mediasize(data); 188168304Spjd ssize = g_get_sectorsize(data); 189163838Spjd if (jsize == -1) { 190163838Spjd /* 191163838Spjd * No journal size specified. 1GB should be safe 192163838Spjd * default. 193163838Spjd */ 194163838Spjd jsize = 1073741824ULL; 195168304Spjd } else { 196168304Spjd if (jsize < 104857600) { 197168304Spjd gctl_error(req, "Journal too small."); 198168304Spjd return; 199168304Spjd } 200168304Spjd if ((jsize % ssize) != 0) { 201168304Spjd gctl_error(req, "Invalid journal size."); 202168304Spjd return; 203168304Spjd } 204163838Spjd } 205163838Spjd if (jsize + ssize >= msize) { 206163838Spjd gctl_error(req, "Provider too small for journalling. " 207163838Spjd "You can try smaller jsize (default is %jd).", 208163838Spjd jsize); 209163838Spjd return; 210163838Spjd } 211163838Spjd md.md_jstart = msize - ssize - jsize; 212163838Spjd md.md_jend = msize - ssize; 213163838Spjd break; 214163838Spjd case 2: 215163838Spjd if (!force && g_journal_fs_using_last_sector(data)) { 216163838Spjd gctl_error(req, "File system on %s is using the last " 217163838Spjd "sector and this operation is going to overwrite " 218163838Spjd "it. Use -f if you really want to do it.", data); 219163838Spjd return; 220163838Spjd } 221163838Spjd journal = gctl_get_ascii(req, "arg1"); 222163838Spjd if (jsize != -1) { 223163838Spjd gctl_error(req, "jsize argument is valid only for " 224163838Spjd "all-in-one configuration."); 225163838Spjd return; 226163838Spjd } 227163838Spjd msize = g_get_mediasize(journal); 228163838Spjd ssize = g_get_sectorsize(journal); 229163838Spjd md.md_jstart = 0; 230163838Spjd md.md_jend = msize - ssize; 231163838Spjd break; 232163838Spjd } 233163838Spjd 234163838Spjd if (g_get_sectorsize(data) != g_get_sectorsize(journal)) { 235163838Spjd gctl_error(req, "Not equal sector sizes."); 236163838Spjd return; 237163838Spjd } 238163838Spjd 239163838Spjd /* 240163838Spjd * Clear last sector first, to spoil all components if device exists. 241163838Spjd */ 242163838Spjd for (i = 0; i < nargs; i++) { 243163838Spjd str = gctl_get_ascii(req, "arg%d", i); 244163838Spjd error = g_metadata_clear(str, NULL); 245163838Spjd if (error != 0) { 246163838Spjd gctl_error(req, "Cannot clear metadata on %s: %s.", str, 247163838Spjd strerror(error)); 248163838Spjd return; 249163838Spjd } 250163838Spjd } 251163838Spjd 252163838Spjd /* 253163838Spjd * Ok, store metadata. 254163838Spjd */ 255163838Spjd for (i = 0; i < nargs; i++) { 256163838Spjd switch (i) { 257163838Spjd case 0: 258163838Spjd str = data; 259163838Spjd md.md_type = GJ_TYPE_DATA; 260163838Spjd if (nargs == 1) 261163838Spjd md.md_type |= GJ_TYPE_JOURNAL; 262163838Spjd break; 263163838Spjd case 1: 264163838Spjd str = journal; 265163838Spjd md.md_type = GJ_TYPE_JOURNAL; 266163838Spjd break; 267163838Spjd } 268163838Spjd md.md_provsize = g_get_mediasize(str); 269163838Spjd assert(md.md_provsize != 0); 270163838Spjd if (!hardcode) 271163838Spjd bzero(md.md_provider, sizeof(md.md_provider)); 272163838Spjd else { 273213662Sae if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 274213662Sae str += sizeof(_PATH_DEV) - 1; 275163838Spjd strlcpy(md.md_provider, str, sizeof(md.md_provider)); 276163838Spjd } 277163838Spjd journal_metadata_encode(&md, sector); 278163838Spjd error = g_metadata_store(str, sector, sizeof(sector)); 279163838Spjd if (error != 0) { 280163838Spjd fprintf(stderr, "Cannot store metadata on %s: %s.\n", 281163838Spjd str, strerror(error)); 282163838Spjd gctl_error(req, "Not fully done."); 283163838Spjd continue; 284163838Spjd } 285163838Spjd if (verbose) 286163838Spjd printf("Metadata value stored on %s.\n", str); 287163838Spjd } 288163838Spjd} 289163838Spjd 290163838Spjdstatic void 291163838Spjdjournal_clear(struct gctl_req *req) 292163838Spjd{ 293163838Spjd const char *name; 294163838Spjd int error, i, nargs; 295163838Spjd 296163838Spjd nargs = gctl_get_int(req, "nargs"); 297163838Spjd if (nargs < 1) { 298163838Spjd gctl_error(req, "Too few arguments."); 299163838Spjd return; 300163838Spjd } 301163838Spjd 302163838Spjd for (i = 0; i < nargs; i++) { 303163838Spjd name = gctl_get_ascii(req, "arg%d", i); 304163838Spjd error = g_metadata_clear(name, G_JOURNAL_MAGIC); 305163838Spjd if (error != 0) { 306163838Spjd fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 307163838Spjd name, strerror(error)); 308163838Spjd gctl_error(req, "Not fully done."); 309163838Spjd continue; 310163838Spjd } 311163838Spjd if (verbose) 312163838Spjd printf("Metadata cleared on %s.\n", name); 313163838Spjd } 314163838Spjd} 315163838Spjd 316163838Spjdstatic void 317163838Spjdjournal_dump(struct gctl_req *req) 318163838Spjd{ 319163838Spjd struct g_journal_metadata md, tmpmd; 320163838Spjd const char *name; 321163838Spjd int error, i, nargs; 322163838Spjd 323163838Spjd nargs = gctl_get_int(req, "nargs"); 324163838Spjd if (nargs < 1) { 325163838Spjd gctl_error(req, "Too few arguments."); 326163838Spjd return; 327163838Spjd } 328163838Spjd 329163838Spjd for (i = 0; i < nargs; i++) { 330163838Spjd name = gctl_get_ascii(req, "arg%d", i); 331163838Spjd error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 332163838Spjd G_JOURNAL_MAGIC); 333163838Spjd if (error != 0) { 334163838Spjd fprintf(stderr, "Cannot read metadata from %s: %s.\n", 335163838Spjd name, strerror(error)); 336163838Spjd gctl_error(req, "Not fully done."); 337163838Spjd continue; 338163838Spjd } 339163838Spjd if (journal_metadata_decode((u_char *)&tmpmd, &md) != 0) { 340163838Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 341163838Spjd name); 342163838Spjd gctl_error(req, "Not fully done."); 343163838Spjd continue; 344163838Spjd } 345163838Spjd printf("Metadata on %s:\n", name); 346163838Spjd journal_metadata_dump(&md); 347163838Spjd printf("\n"); 348163838Spjd } 349163838Spjd} 350