1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <errno.h> 34#include <paths.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <string.h> 38#include <strings.h> 39#include <assert.h> 40#include <libgeom.h> 41#include <geom/concat/g_concat.h> 42 43#include "core/geom.h" 44#include "misc/subr.h" 45 46 47uint32_t lib_version = G_LIB_VERSION; 48uint32_t version = G_CONCAT_VERSION; 49 50static void concat_main(struct gctl_req *req, unsigned flags); 51static void concat_clear(struct gctl_req *req); 52static void concat_dump(struct gctl_req *req); 53static void concat_label(struct gctl_req *req); 54 55struct g_command class_commands[] = { 56 { "clear", G_FLAG_VERBOSE, concat_main, G_NULL_OPTS, 57 "[-v] prov ..." 58 }, 59 { "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL, G_NULL_OPTS, 60 "[-v] name prov ..." 61 }, 62 { "destroy", G_FLAG_VERBOSE, NULL, 63 { 64 { 'f', "force", NULL, G_TYPE_BOOL }, 65 G_OPT_SENTINEL 66 }, 67 "[-fv] name ..." 68 }, 69 { "dump", 0, concat_main, G_NULL_OPTS, 70 "prov ..." 71 }, 72 { "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, concat_main, 73 { 74 { 'h', "hardcode", NULL, G_TYPE_BOOL }, 75 G_OPT_SENTINEL 76 }, 77 "[-hv] name prov ..." 78 }, 79 { "stop", G_FLAG_VERBOSE, NULL, 80 { 81 { 'f', "force", NULL, G_TYPE_BOOL }, 82 G_OPT_SENTINEL 83 }, 84 "[-fv] name ..." 85 }, 86 G_CMD_SENTINEL 87}; 88 89static int verbose = 0; 90 91static void 92concat_main(struct gctl_req *req, unsigned flags) 93{ 94 const char *name; 95 96 if ((flags & G_FLAG_VERBOSE) != 0) 97 verbose = 1; 98 99 name = gctl_get_ascii(req, "verb"); 100 if (name == NULL) { 101 gctl_error(req, "No '%s' argument.", "verb"); 102 return; 103 } 104 if (strcmp(name, "label") == 0) 105 concat_label(req); 106 else if (strcmp(name, "clear") == 0) 107 concat_clear(req); 108 else if (strcmp(name, "dump") == 0) 109 concat_dump(req); 110 else 111 gctl_error(req, "Unknown command: %s.", name); 112} 113 114static void 115concat_label(struct gctl_req *req) 116{ 117 struct g_concat_metadata md; 118 u_char sector[512]; 119 const char *name; 120 int error, i, hardcode, nargs; 121 122 bzero(sector, sizeof(sector)); 123 nargs = gctl_get_int(req, "nargs"); 124 if (nargs < 2) { 125 gctl_error(req, "Too few arguments."); 126 return; 127 } 128 hardcode = gctl_get_int(req, "hardcode"); 129 130 /* 131 * Clear last sector first to spoil all components if device exists. 132 */ 133 for (i = 1; i < nargs; i++) { 134 name = gctl_get_ascii(req, "arg%d", i); 135 error = g_metadata_clear(name, NULL); 136 if (error != 0) { 137 gctl_error(req, "Can't store metadata on %s: %s.", name, 138 strerror(error)); 139 return; 140 } 141 } 142 143 strlcpy(md.md_magic, G_CONCAT_MAGIC, sizeof(md.md_magic)); 144 md.md_version = G_CONCAT_VERSION; 145 name = gctl_get_ascii(req, "arg0"); 146 strlcpy(md.md_name, name, sizeof(md.md_name)); 147 md.md_id = arc4random(); 148 md.md_all = nargs - 1; 149 150 /* 151 * Ok, store metadata. 152 */ 153 for (i = 1; i < nargs; i++) { 154 name = gctl_get_ascii(req, "arg%d", i); 155 md.md_no = i - 1; 156 if (!hardcode) 157 bzero(md.md_provider, sizeof(md.md_provider)); 158 else { 159 if (strncmp(name, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0) 160 name += sizeof(_PATH_DEV) - 1; 161 strlcpy(md.md_provider, name, sizeof(md.md_provider)); 162 } 163 md.md_provsize = g_get_mediasize(name); 164 if (md.md_provsize == 0) { 165 fprintf(stderr, "Can't get mediasize of %s: %s.\n", 166 name, strerror(errno)); 167 gctl_error(req, "Not fully done."); 168 continue; 169 } 170 concat_metadata_encode(&md, sector); 171 error = g_metadata_store(name, sector, sizeof(sector)); 172 if (error != 0) { 173 fprintf(stderr, "Can't store metadata on %s: %s.\n", 174 name, strerror(error)); 175 gctl_error(req, "Not fully done."); 176 continue; 177 } 178 if (verbose) 179 printf("Metadata value stored on %s.\n", name); 180 } 181} 182 183static void 184concat_clear(struct gctl_req *req) 185{ 186 const char *name; 187 int error, i, nargs; 188 189 nargs = gctl_get_int(req, "nargs"); 190 if (nargs < 1) { 191 gctl_error(req, "Too few arguments."); 192 return; 193 } 194 195 for (i = 0; i < nargs; i++) { 196 name = gctl_get_ascii(req, "arg%d", i); 197 error = g_metadata_clear(name, G_CONCAT_MAGIC); 198 if (error != 0) { 199 fprintf(stderr, "Can't clear metadata on %s: %s.\n", 200 name, strerror(error)); 201 gctl_error(req, "Not fully done."); 202 continue; 203 } 204 if (verbose) 205 printf("Metadata cleared on %s.\n", name); 206 } 207} 208 209static void 210concat_metadata_dump(const struct g_concat_metadata *md) 211{ 212 213 printf(" Magic string: %s\n", md->md_magic); 214 printf(" Metadata version: %u\n", (u_int)md->md_version); 215 printf(" Device name: %s\n", md->md_name); 216 printf(" Device ID: %u\n", (u_int)md->md_id); 217 printf(" Disk number: %u\n", (u_int)md->md_no); 218 printf("Total number of disks: %u\n", (u_int)md->md_all); 219 printf(" Hardcoded provider: %s\n", md->md_provider); 220} 221 222static void 223concat_dump(struct gctl_req *req) 224{ 225 struct g_concat_metadata md, tmpmd; 226 const char *name; 227 int error, i, nargs; 228 229 nargs = gctl_get_int(req, "nargs"); 230 if (nargs < 1) { 231 gctl_error(req, "Too few arguments."); 232 return; 233 } 234 235 for (i = 0; i < nargs; i++) { 236 name = gctl_get_ascii(req, "arg%d", i); 237 error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd), 238 G_CONCAT_MAGIC); 239 if (error != 0) { 240 fprintf(stderr, "Can't read metadata from %s: %s.\n", 241 name, strerror(error)); 242 gctl_error(req, "Not fully done."); 243 continue; 244 } 245 concat_metadata_decode((u_char *)&tmpmd, &md); 246 printf("Metadata on %s:\n", name); 247 concat_metadata_dump(&md); 248 printf("\n"); 249 } 250} 251