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