1/*- 2 * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: stable/11/sys/geom/label/g_label.c 346559 2019-04-22 15:09:47Z ian $"); 29 30#include "opt_geom.h" 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/kernel.h> 35#include <sys/module.h> 36#include <sys/lock.h> 37#include <sys/mutex.h> 38#include <sys/bio.h> 39#include <sys/ctype.h> 40#include <sys/malloc.h> 41#include <sys/libkern.h> 42#include <sys/sbuf.h> 43#include <sys/stddef.h> 44#include <sys/sysctl.h> 45#include <geom/geom.h> 46#include <geom/geom_slice.h> 47#include <geom/label/g_label.h> 48 49FEATURE(geom_label, "GEOM labeling support"); 50 51SYSCTL_DECL(_kern_geom); 52SYSCTL_NODE(_kern_geom, OID_AUTO, label, CTLFLAG_RW, 0, "GEOM_LABEL stuff"); 53u_int g_label_debug = 0; 54SYSCTL_UINT(_kern_geom_label, OID_AUTO, debug, CTLFLAG_RWTUN, &g_label_debug, 0, 55 "Debug level"); 56 57static int g_label_destroy_geom(struct gctl_req *req, struct g_class *mp, 58 struct g_geom *gp); 59static int g_label_destroy(struct g_geom *gp, boolean_t force); 60static struct g_geom *g_label_taste(struct g_class *mp, struct g_provider *pp, 61 int flags __unused); 62static void g_label_config(struct gctl_req *req, struct g_class *mp, 63 const char *verb); 64 65struct g_class g_label_class = { 66 .name = G_LABEL_CLASS_NAME, 67 .version = G_VERSION, 68 .ctlreq = g_label_config, 69 .taste = g_label_taste, 70 .destroy_geom = g_label_destroy_geom 71}; 72 73/* 74 * To add a new file system where you want to look for volume labels, 75 * you have to: 76 * 1. Add a file g_label_<file system>.c which implements labels recognition. 77 * 2. Add an 'extern const struct g_label_desc g_label_<file system>;' into 78 * g_label.h file. 79 * 3. Add an element to the table below '&g_label_<file system>,'. 80 * 4. Add your file to sys/conf/files. 81 * 5. Add your file to sys/modules/geom/geom_label/Makefile. 82 * 6. Add your file system to manual page sbin/geom/class/label/glabel.8. 83 */ 84const struct g_label_desc *g_labels[] = { 85 &g_label_gpt, 86 &g_label_gpt_uuid, 87#ifdef GEOM_LABEL 88 &g_label_ufs_id, 89 &g_label_ufs_volume, 90 &g_label_iso9660, 91 &g_label_msdosfs, 92 &g_label_ext2fs, 93 &g_label_reiserfs, 94 &g_label_ntfs, 95 &g_label_disk_ident, 96 &g_label_flashmap, 97#endif 98 NULL 99}; 100 101void 102g_label_rtrim(char *label, size_t size) 103{ 104 ptrdiff_t i; 105 106 for (i = size - 1; i >= 0; i--) { 107 if (label[i] == '\0') 108 continue; 109 else if (label[i] == ' ') 110 label[i] = '\0'; 111 else 112 break; 113 } 114} 115 116static int 117g_label_destroy_geom(struct gctl_req *req __unused, struct g_class *mp, 118 struct g_geom *gp __unused) 119{ 120 121 /* 122 * XXX: Unloading a class which is using geom_slice:1.56 is currently 123 * XXX: broken, so we deny unloading when we have geoms. 124 */ 125 return (EOPNOTSUPP); 126} 127 128static void 129g_label_orphan(struct g_consumer *cp) 130{ 131 132 G_LABEL_DEBUG(1, "Label %s removed.", 133 LIST_FIRST(&cp->geom->provider)->name); 134 g_slice_orphan(cp); 135} 136 137static void 138g_label_spoiled(struct g_consumer *cp) 139{ 140 141 G_LABEL_DEBUG(1, "Label %s removed.", 142 LIST_FIRST(&cp->geom->provider)->name); 143 g_slice_spoiled(cp); 144} 145 146static void 147g_label_resize(struct g_consumer *cp) 148{ 149 150 G_LABEL_DEBUG(1, "Label %s resized.", 151 LIST_FIRST(&cp->geom->provider)->name); 152 153 g_slice_config(cp->geom, 0, G_SLICE_CONFIG_FORCE, (off_t)0, 154 cp->provider->mediasize, cp->provider->sectorsize, "notused"); 155} 156 157static int 158g_label_is_name_ok(const char *label) 159{ 160 const char *s; 161 162 /* Check if the label starts from ../ */ 163 if (strncmp(label, "../", 3) == 0) 164 return (0); 165 /* Check if the label contains /../ */ 166 if (strstr(label, "/../") != NULL) 167 return (0); 168 /* Check if the label ends at ../ */ 169 if ((s = strstr(label, "/..")) != NULL && s[3] == '\0') 170 return (0); 171 return (1); 172} 173 174static void 175g_label_mangle_name(char *label, size_t size) 176{ 177 struct sbuf *sb; 178 const u_char *c; 179 180 sb = sbuf_new(NULL, NULL, size, SBUF_FIXEDLEN); 181 for (c = label; *c != '\0'; c++) { 182 if (!isprint(*c) || isspace(*c) || *c =='"' || *c == '%') 183 sbuf_printf(sb, "%%%02X", *c); 184 else 185 sbuf_putc(sb, *c); 186 } 187 if (sbuf_finish(sb) != 0) 188 label[0] = '\0'; 189 else 190 strlcpy(label, sbuf_data(sb), size); 191 sbuf_delete(sb); 192} 193 194static struct g_geom * 195g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, 196 const char *label, const char *dir, off_t mediasize) 197{ 198 struct g_geom *gp; 199 struct g_provider *pp2; 200 struct g_consumer *cp; 201 char name[64]; 202 203 g_topology_assert(); 204 205 if (!g_label_is_name_ok(label)) { 206 G_LABEL_DEBUG(0, "%s contains suspicious label, skipping.", 207 pp->name); 208 G_LABEL_DEBUG(1, "%s suspicious label is: %s", pp->name, label); 209 if (req != NULL) 210 gctl_error(req, "Label name %s is invalid.", label); 211 return (NULL); 212 } 213 gp = NULL; 214 cp = NULL; 215 snprintf(name, sizeof(name), "%s/%s", dir, label); 216 LIST_FOREACH(gp, &mp->geom, geom) { 217 pp2 = LIST_FIRST(&gp->provider); 218 if (pp2 == NULL) 219 continue; 220 if ((pp2->flags & G_PF_ORPHAN) != 0) 221 continue; 222 if (strcmp(pp2->name, name) == 0) { 223 G_LABEL_DEBUG(1, "Label %s(%s) already exists (%s).", 224 label, name, pp->name); 225 if (req != NULL) { 226 gctl_error(req, "Provider %s already exists.", 227 name); 228 } 229 return (NULL); 230 } 231 } 232 gp = g_slice_new(mp, 1, pp, &cp, NULL, 0, NULL); 233 if (gp == NULL) { 234 G_LABEL_DEBUG(0, "Cannot create slice %s.", label); 235 if (req != NULL) 236 gctl_error(req, "Cannot create slice %s.", label); 237 return (NULL); 238 } 239 gp->orphan = g_label_orphan; 240 gp->spoiled = g_label_spoiled; 241 gp->resize = g_label_resize; 242 g_access(cp, -1, 0, 0); 243 g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t)0, mediasize, 244 pp->sectorsize, "%s", name); 245 G_LABEL_DEBUG(1, "Label for provider %s is %s.", pp->name, name); 246 return (gp); 247} 248 249static int 250g_label_destroy(struct g_geom *gp, boolean_t force) 251{ 252 struct g_provider *pp; 253 254 g_topology_assert(); 255 pp = LIST_FIRST(&gp->provider); 256 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 257 if (force) { 258 G_LABEL_DEBUG(0, "Provider %s is still open, so it " 259 "can't be definitely removed.", pp->name); 260 } else { 261 G_LABEL_DEBUG(1, 262 "Provider %s is still open (r%dw%de%d).", pp->name, 263 pp->acr, pp->acw, pp->ace); 264 return (EBUSY); 265 } 266 } else if (pp != NULL) 267 G_LABEL_DEBUG(1, "Label %s removed.", pp->name); 268 g_slice_spoiled(LIST_FIRST(&gp->consumer)); 269 return (0); 270} 271 272static int 273g_label_read_metadata(struct g_consumer *cp, struct g_label_metadata *md) 274{ 275 struct g_provider *pp; 276 u_char *buf; 277 int error; 278 279 g_topology_assert(); 280 281 pp = cp->provider; 282 g_topology_unlock(); 283 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 284 &error); 285 g_topology_lock(); 286 if (buf == NULL) 287 return (error); 288 /* Decode metadata. */ 289 label_metadata_decode(buf, md); 290 g_free(buf); 291 292 return (0); 293} 294 295static void 296g_label_orphan_taste(struct g_consumer *cp __unused) 297{ 298 299 KASSERT(1 == 0, ("%s called?", __func__)); 300} 301 302static void 303g_label_start_taste(struct bio *bp __unused) 304{ 305 306 KASSERT(1 == 0, ("%s called?", __func__)); 307} 308 309static int 310g_label_access_taste(struct g_provider *pp __unused, int dr __unused, 311 int dw __unused, int de __unused) 312{ 313 314 KASSERT(1 == 0, ("%s called", __func__)); 315 return (EOPNOTSUPP); 316} 317 318static struct g_geom * 319g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 320{ 321 struct g_label_metadata md; 322 struct g_consumer *cp; 323 struct g_geom *gp; 324 int i; 325 326 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 327 g_topology_assert(); 328 329 G_LABEL_DEBUG(2, "Tasting %s.", pp->name); 330 331 /* Skip providers that are already open for writing. */ 332 if (pp->acw > 0) 333 return (NULL); 334 335 if (strcmp(pp->geom->class->name, mp->name) == 0) 336 return (NULL); 337 338 gp = g_new_geomf(mp, "label:taste"); 339 gp->start = g_label_start_taste; 340 gp->access = g_label_access_taste; 341 gp->orphan = g_label_orphan_taste; 342 cp = g_new_consumer(gp); 343 g_attach(cp, pp); 344 if (g_access(cp, 1, 0, 0) != 0) 345 goto end; 346 do { 347 if (g_label_read_metadata(cp, &md) != 0) 348 break; 349 if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0) 350 break; 351 if (md.md_version > G_LABEL_VERSION) { 352 printf("geom_label.ko module is too old to handle %s.\n", 353 pp->name); 354 break; 355 } 356 357 /* 358 * Backward compatibility: 359 */ 360 /* 361 * There was no md_provsize field in earlier versions of 362 * metadata. 363 */ 364 if (md.md_version < 2) 365 md.md_provsize = pp->mediasize; 366 367 if (md.md_provsize != pp->mediasize) 368 break; 369 370 g_label_create(NULL, mp, pp, md.md_label, G_LABEL_DIR, 371 pp->mediasize - pp->sectorsize); 372 } while (0); 373 for (i = 0; g_labels[i] != NULL; i++) { 374 char label[128]; 375 376 if (g_labels[i]->ld_enabled == 0) 377 continue; 378 g_topology_unlock(); 379 g_labels[i]->ld_taste(cp, label, sizeof(label)); 380 g_label_mangle_name(label, sizeof(label)); 381 g_topology_lock(); 382 if (label[0] == '\0') 383 continue; 384 g_label_create(NULL, mp, pp, label, g_labels[i]->ld_dir, 385 pp->mediasize); 386 } 387 g_access(cp, -1, 0, 0); 388end: 389 g_detach(cp); 390 g_destroy_consumer(cp); 391 g_destroy_geom(gp); 392 return (NULL); 393} 394 395static void 396g_label_ctl_create(struct gctl_req *req, struct g_class *mp) 397{ 398 struct g_provider *pp; 399 const char *name; 400 int *nargs; 401 402 g_topology_assert(); 403 404 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 405 if (nargs == NULL) { 406 gctl_error(req, "No '%s' argument", "nargs"); 407 return; 408 } 409 if (*nargs != 2) { 410 gctl_error(req, "Invalid number of arguments."); 411 return; 412 } 413 /* 414 * arg1 is the name of provider. 415 */ 416 name = gctl_get_asciiparam(req, "arg1"); 417 if (name == NULL) { 418 gctl_error(req, "No 'arg%d' argument", 1); 419 return; 420 } 421 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 422 name += strlen("/dev/"); 423 pp = g_provider_by_name(name); 424 if (pp == NULL) { 425 G_LABEL_DEBUG(1, "Provider %s is invalid.", name); 426 gctl_error(req, "Provider %s is invalid.", name); 427 return; 428 } 429 /* 430 * arg0 is the label. 431 */ 432 name = gctl_get_asciiparam(req, "arg0"); 433 if (name == NULL) { 434 gctl_error(req, "No 'arg%d' argument", 0); 435 return; 436 } 437 g_label_create(req, mp, pp, name, G_LABEL_DIR, pp->mediasize); 438} 439 440static const char * 441g_label_skip_dir(const char *name) 442{ 443 char path[64]; 444 u_int i; 445 446 if (strncmp(name, "/dev/", strlen("/dev/")) == 0) 447 name += strlen("/dev/"); 448 if (strncmp(name, G_LABEL_DIR "/", strlen(G_LABEL_DIR "/")) == 0) 449 name += strlen(G_LABEL_DIR "/"); 450 for (i = 0; g_labels[i] != NULL; i++) { 451 snprintf(path, sizeof(path), "%s/", g_labels[i]->ld_dir); 452 if (strncmp(name, path, strlen(path)) == 0) { 453 name += strlen(path); 454 break; 455 } 456 } 457 return (name); 458} 459 460static struct g_geom * 461g_label_find_geom(struct g_class *mp, const char *name) 462{ 463 struct g_geom *gp; 464 struct g_provider *pp; 465 const char *pname; 466 467 name = g_label_skip_dir(name); 468 LIST_FOREACH(gp, &mp->geom, geom) { 469 pp = LIST_FIRST(&gp->provider); 470 pname = g_label_skip_dir(pp->name); 471 if (strcmp(pname, name) == 0) 472 return (gp); 473 } 474 return (NULL); 475} 476 477static void 478g_label_ctl_destroy(struct gctl_req *req, struct g_class *mp) 479{ 480 int *nargs, *force, error, i; 481 struct g_geom *gp; 482 const char *name; 483 char param[16]; 484 485 g_topology_assert(); 486 487 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 488 if (nargs == NULL) { 489 gctl_error(req, "No '%s' argument", "nargs"); 490 return; 491 } 492 if (*nargs <= 0) { 493 gctl_error(req, "Missing device(s)."); 494 return; 495 } 496 force = gctl_get_paraml(req, "force", sizeof(*force)); 497 if (force == NULL) { 498 gctl_error(req, "No 'force' argument"); 499 return; 500 } 501 502 for (i = 0; i < *nargs; i++) { 503 snprintf(param, sizeof(param), "arg%d", i); 504 name = gctl_get_asciiparam(req, param); 505 if (name == NULL) { 506 gctl_error(req, "No 'arg%d' argument", i); 507 return; 508 } 509 gp = g_label_find_geom(mp, name); 510 if (gp == NULL) { 511 G_LABEL_DEBUG(1, "Label %s is invalid.", name); 512 gctl_error(req, "Label %s is invalid.", name); 513 return; 514 } 515 error = g_label_destroy(gp, *force); 516 if (error != 0) { 517 gctl_error(req, "Cannot destroy label %s (error=%d).", 518 LIST_FIRST(&gp->provider)->name, error); 519 return; 520 } 521 } 522} 523 524static void 525g_label_config(struct gctl_req *req, struct g_class *mp, const char *verb) 526{ 527 uint32_t *version; 528 529 g_topology_assert(); 530 531 version = gctl_get_paraml(req, "version", sizeof(*version)); 532 if (version == NULL) { 533 gctl_error(req, "No '%s' argument.", "version"); 534 return; 535 } 536 if (*version != G_LABEL_VERSION) { 537 gctl_error(req, "Userland and kernel parts are out of sync."); 538 return; 539 } 540 541 if (strcmp(verb, "create") == 0) { 542 g_label_ctl_create(req, mp); 543 return; 544 } else if (strcmp(verb, "destroy") == 0 || 545 strcmp(verb, "stop") == 0) { 546 g_label_ctl_destroy(req, mp); 547 return; 548 } 549 550 gctl_error(req, "Unknown verb."); 551} 552 553DECLARE_GEOM_CLASS(g_label_class, g_label); 554MODULE_VERSION(geom_label, 0); 555