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: releng/10.3/sbin/geom/class/journal/geom_journal.c 213662 2010-10-09 20:20:27Z ae $"); 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 145163838Spjd nargs = gctl_get_int(req, "nargs"); 146163864Spjd str = NULL; /* gcc */ 147163838Spjd 148163838Spjd strlcpy(md.md_magic, G_JOURNAL_MAGIC, sizeof(md.md_magic)); 149163838Spjd md.md_version = G_JOURNAL_VERSION; 150163838Spjd md.md_id = arc4random(); 151163838Spjd md.md_joffset = 0; 152163838Spjd md.md_jid = 0; 153163838Spjd md.md_flags = GJ_FLAG_CLEAN; 154163838Spjd checksum = gctl_get_int(req, "checksum"); 155163838Spjd if (checksum) 156163838Spjd md.md_flags |= GJ_FLAG_CHECKSUM; 157163838Spjd force = gctl_get_int(req, "force"); 158163838Spjd hardcode = gctl_get_int(req, "hardcode"); 159163838Spjd 160163838Spjd if (nargs != 1 && nargs != 2) { 161163838Spjd gctl_error(req, "Invalid number of arguments."); 162163838Spjd return; 163163838Spjd } 164163838Spjd 165163838Spjd /* Verify the given providers. */ 166163838Spjd for (i = 0; i < nargs; i++) { 167163838Spjd str = gctl_get_ascii(req, "arg%d", i); 168163838Spjd if (g_get_mediasize(str) == 0) { 169163838Spjd gctl_error(req, "Invalid provider %s.", str); 170163838Spjd return; 171163838Spjd } 172163838Spjd } 173163838Spjd 174163838Spjd data = gctl_get_ascii(req, "arg0"); 175163838Spjd jsize = gctl_get_intmax(req, "jsize"); 176163838Spjd journal = NULL; 177163838Spjd switch (nargs) { 178163838Spjd case 1: 179163838Spjd if (!force && g_journal_fs_exists(data)) { 180163838Spjd gctl_error(req, "File system exists on %s and this " 181168304Spjd "operation would destroy it.\nUse -f if you " 182163838Spjd "really want to do it.", data); 183163838Spjd return; 184163838Spjd } 185163838Spjd journal = data; 186168304Spjd msize = g_get_mediasize(data); 187168304Spjd ssize = g_get_sectorsize(data); 188163838Spjd if (jsize == -1) { 189163838Spjd /* 190163838Spjd * No journal size specified. 1GB should be safe 191163838Spjd * default. 192163838Spjd */ 193163838Spjd jsize = 1073741824ULL; 194168304Spjd } else { 195168304Spjd if (jsize < 104857600) { 196168304Spjd gctl_error(req, "Journal too small."); 197168304Spjd return; 198168304Spjd } 199168304Spjd if ((jsize % ssize) != 0) { 200168304Spjd gctl_error(req, "Invalid journal size."); 201168304Spjd return; 202168304Spjd } 203163838Spjd } 204163838Spjd if (jsize + ssize >= msize) { 205163838Spjd gctl_error(req, "Provider too small for journalling. " 206163838Spjd "You can try smaller jsize (default is %jd).", 207163838Spjd jsize); 208163838Spjd return; 209163838Spjd } 210163838Spjd md.md_jstart = msize - ssize - jsize; 211163838Spjd md.md_jend = msize - ssize; 212163838Spjd break; 213163838Spjd case 2: 214163838Spjd if (!force && g_journal_fs_using_last_sector(data)) { 215163838Spjd gctl_error(req, "File system on %s is using the last " 216163838Spjd "sector and this operation is going to overwrite " 217163838Spjd "it. Use -f if you really want to do it.", data); 218163838Spjd return; 219163838Spjd } 220163838Spjd journal = gctl_get_ascii(req, "arg1"); 221163838Spjd if (jsize != -1) { 222163838Spjd gctl_error(req, "jsize argument is valid only for " 223163838Spjd "all-in-one configuration."); 224163838Spjd return; 225163838Spjd } 226163838Spjd msize = g_get_mediasize(journal); 227163838Spjd ssize = g_get_sectorsize(journal); 228163838Spjd md.md_jstart = 0; 229163838Spjd md.md_jend = msize - ssize; 230163838Spjd break; 231163838Spjd } 232163838Spjd 233163838Spjd if (g_get_sectorsize(data) != g_get_sectorsize(journal)) { 234163838Spjd gctl_error(req, "Not equal sector sizes."); 235163838Spjd return; 236163838Spjd } 237163838Spjd 238163838Spjd /* 239163838Spjd * Clear last sector first, to spoil all components if device exists. 240163838Spjd */ 241163838Spjd for (i = 0; i < nargs; i++) { 242163838Spjd str = gctl_get_ascii(req, "arg%d", i); 243163838Spjd error = g_metadata_clear(str, NULL); 244163838Spjd if (error != 0) { 245163838Spjd gctl_error(req, "Cannot clear metadata on %s: %s.", str, 246163838Spjd strerror(error)); 247163838Spjd return; 248163838Spjd } 249163838Spjd } 250163838Spjd 251163838Spjd /* 252163838Spjd * Ok, store metadata. 253163838Spjd */ 254163838Spjd for (i = 0; i < nargs; i++) { 255163838Spjd switch (i) { 256163838Spjd case 0: 257163838Spjd str = data; 258163838Spjd md.md_type = GJ_TYPE_DATA; 259163838Spjd if (nargs == 1) 260163838Spjd md.md_type |= GJ_TYPE_JOURNAL; 261163838Spjd break; 262163838Spjd case 1: 263163838Spjd str = journal; 264163838Spjd md.md_type = GJ_TYPE_JOURNAL; 265163838Spjd break; 266163838Spjd } 267163838Spjd md.md_provsize = g_get_mediasize(str); 268163838Spjd assert(md.md_provsize != 0); 269163838Spjd if (!hardcode) 270163838Spjd bzero(md.md_provider, sizeof(md.md_provider)); 271163838Spjd else { 272213662Sae if (strncmp(str, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 273213662Sae str += sizeof(_PATH_DEV) - 1; 274163838Spjd strlcpy(md.md_provider, str, sizeof(md.md_provider)); 275163838Spjd } 276163838Spjd journal_metadata_encode(&md, sector); 277163838Spjd error = g_metadata_store(str, sector, sizeof(sector)); 278163838Spjd if (error != 0) { 279163838Spjd fprintf(stderr, "Cannot store metadata on %s: %s.\n", 280163838Spjd str, strerror(error)); 281163838Spjd gctl_error(req, "Not fully done."); 282163838Spjd continue; 283163838Spjd } 284163838Spjd if (verbose) 285163838Spjd printf("Metadata value stored on %s.\n", str); 286163838Spjd } 287163838Spjd} 288163838Spjd 289163838Spjdstatic void 290163838Spjdjournal_clear(struct gctl_req *req) 291163838Spjd{ 292163838Spjd const char *name; 293163838Spjd int error, i, nargs; 294163838Spjd 295163838Spjd nargs = gctl_get_int(req, "nargs"); 296163838Spjd if (nargs < 1) { 297163838Spjd gctl_error(req, "Too few arguments."); 298163838Spjd return; 299163838Spjd } 300163838Spjd 301163838Spjd for (i = 0; i < nargs; i++) { 302163838Spjd name = gctl_get_ascii(req, "arg%d", i); 303163838Spjd error = g_metadata_clear(name, G_JOURNAL_MAGIC); 304163838Spjd if (error != 0) { 305163838Spjd fprintf(stderr, "Cannot clear metadata on %s: %s.\n", 306163838Spjd name, strerror(error)); 307163838Spjd gctl_error(req, "Not fully done."); 308163838Spjd continue; 309163838Spjd } 310163838Spjd if (verbose) 311163838Spjd printf("Metadata cleared on %s.\n", name); 312163838Spjd } 313163838Spjd} 314163838Spjd 315163838Spjdstatic void 316163838Spjdjournal_dump(struct gctl_req *req) 317163838Spjd{ 318163838Spjd struct g_journal_metadata md, tmpmd; 319163838Spjd const char *name; 320163838Spjd int error, i, nargs; 321163838Spjd 322163838Spjd nargs = gctl_get_int(req, "nargs"); 323163838Spjd if (nargs < 1) { 324163838Spjd gctl_error(req, "Too few arguments."); 325163838Spjd return; 326163838Spjd } 327163838Spjd 328163838Spjd for (i = 0; i < nargs; i++) { 329163838Spjd name = gctl_get_ascii(req, "arg%d", i); 330163838Spjd error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 331163838Spjd G_JOURNAL_MAGIC); 332163838Spjd if (error != 0) { 333163838Spjd fprintf(stderr, "Cannot read metadata from %s: %s.\n", 334163838Spjd name, strerror(error)); 335163838Spjd gctl_error(req, "Not fully done."); 336163838Spjd continue; 337163838Spjd } 338163838Spjd if (journal_metadata_decode((u_char *)&tmpmd, &md) != 0) { 339163838Spjd fprintf(stderr, "MD5 hash mismatch for %s, skipping.\n", 340163838Spjd name); 341163838Spjd gctl_error(req, "Not fully done."); 342163838Spjd continue; 343163838Spjd } 344163838Spjd printf("Metadata on %s:\n", name); 345163838Spjd journal_metadata_dump(&md); 346163838Spjd printf("\n"); 347163838Spjd } 348163838Spjd} 349