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 47 uint32_t lib_version = G_LIB_VERSION; 48 uint32_t version = G_CONCAT_VERSION; 49 50 static void concat_main(struct gctl_req *req, unsigned flags); 51 static void concat_clear(struct gctl_req *req); 52 static void concat_dump(struct gctl_req *req); 53 static void concat_label(struct gctl_req *req); 54 55 struct 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 89 static int verbose = 0; 90 91 static void 92 concat_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 114 static void 115 concat_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 183 static void 184 concat_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 209 static void 210 concat_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 222 static void 223 concat_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