1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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 "opt_geom.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/module.h> 38 #include <sys/lock.h> 39 #include <sys/mutex.h> 40 #include <sys/bio.h> 41 #include <sys/ctype.h> 42 #include <sys/malloc.h> 43 #include <sys/libkern.h> 44 #include <sys/sbuf.h> 45 #include <sys/stddef.h> 46 #include <sys/sysctl.h> 47 #include <geom/geom.h> 48 #include <geom/geom_dbg.h> 49 #include <geom/geom_slice.h> 50 #include <geom/label/g_label.h> 51 52 FEATURE(geom_label, "GEOM labeling support"); 53 54 SYSCTL_DECL(_kern_geom); 55 SYSCTL_NODE(_kern_geom, OID_AUTO, label, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 56 "GEOM_LABEL stuff"); 57 u_int g_label_debug = 0; 58 SYSCTL_UINT(_kern_geom_label, OID_AUTO, debug, CTLFLAG_RWTUN, &g_label_debug, 0, 59 "Debug level"); 60 61 static int g_label_destroy_geom(struct gctl_req *req, struct g_class *mp, 62 struct g_geom *gp); 63 static int g_label_destroy(struct g_geom *gp, boolean_t force); 64 static struct g_geom *g_label_taste(struct g_class *mp, struct g_provider *pp, 65 int flags __unused); 66 static void g_label_generic_taste(struct g_consumer *, char *, size_t); 67 static void g_label_config(struct gctl_req *req, struct g_class *mp, 68 const char *verb); 69 70 #define G_LABEL_DIRPREFIX "label/" 71 72 struct g_class g_label_class = { 73 .name = G_LABEL_CLASS_NAME, 74 .version = G_VERSION, 75 .ctlreq = g_label_config, 76 .taste = g_label_taste, 77 .destroy_geom = g_label_destroy_geom 78 }; 79 80 static struct g_label_desc g_label_generic = { 81 .ld_taste = g_label_generic_taste, 82 .ld_dirprefix = G_LABEL_DIRPREFIX, 83 .ld_enabled = 1 84 }; 85 86 /* 87 * To add a new file system where you want to look for volume labels, 88 * you have to: 89 * 1. Add a file g_label_<file system>.c which implements labels recognition. 90 * 2. Add an 'extern const struct g_label_desc g_label_<file system>;' into 91 * g_label.h file. 92 * 3. Add an element to the table below '&g_label_<file system>,'. 93 * 4. Add your file to sys/conf/files. 94 * 5. Add your file to sys/modules/geom/geom_label/Makefile. 95 * 6. Add your file system to manual page sbin/geom/class/label/glabel.8. 96 */ 97 const struct g_label_desc *g_labels[] = { 98 &g_label_gpt, 99 &g_label_gpt_uuid, 100 #ifdef GEOM_LABEL 101 &g_label_ufs_id, 102 &g_label_ufs_volume, 103 &g_label_iso9660, 104 &g_label_msdosfs, 105 &g_label_ext2fs, 106 &g_label_reiserfs, 107 &g_label_ntfs, 108 &g_label_disk_ident, 109 &g_label_flashmap, 110 #endif 111 &g_label_generic, 112 NULL 113 }; 114 115 void 116 g_label_rtrim(char *label, size_t size) 117 { 118 ptrdiff_t i; 119 120 for (i = size - 1; i >= 0; i--) { 121 if (label[i] == '\0') 122 continue; 123 else if (label[i] == ' ') 124 label[i] = '\0'; 125 else 126 break; 127 } 128 } 129 130 static int 131 g_label_destroy_geom(struct gctl_req *req __unused, struct g_class *mp, 132 struct g_geom *gp __unused) 133 { 134 135 /* 136 * XXX: Unloading a class which is using geom_slice:1.56 is currently 137 * XXX: broken, so we deny unloading when we have geoms. 138 */ 139 return (EOPNOTSUPP); 140 } 141 142 static void 143 g_label_orphan(struct g_consumer *cp) 144 { 145 146 G_LABEL_DEBUG(1, "Label %s removed.", 147 LIST_FIRST(&cp->geom->provider)->name); 148 g_slice_orphan(cp); 149 } 150 151 static void 152 g_label_spoiled(struct g_consumer *cp) 153 { 154 155 G_LABEL_DEBUG(1, "Label %s removed.", 156 LIST_FIRST(&cp->geom->provider)->name); 157 g_slice_spoiled(cp); 158 } 159 160 static void 161 g_label_resize(struct g_consumer *cp) 162 { 163 164 G_LABEL_DEBUG(1, "Label %s resized.", 165 LIST_FIRST(&cp->geom->provider)->name); 166 167 g_slice_config(cp->geom, 0, G_SLICE_CONFIG_FORCE, (off_t)0, 168 cp->provider->mediasize, cp->provider->sectorsize, "notused"); 169 } 170 171 static int 172 g_label_is_name_ok(const char *label) 173 { 174 const char *s; 175 176 /* Check if the label starts from ../ */ 177 if (strncmp(label, "../", 3) == 0) 178 return (0); 179 /* Check if the label contains /../ */ 180 if (strstr(label, "/../") != NULL) 181 return (0); 182 /* Check if the label ends at ../ */ 183 if ((s = strstr(label, "/..")) != NULL && s[3] == '\0') 184 return (0); 185 return (1); 186 } 187 188 static void 189 g_label_mangle_name(char *label, size_t size) 190 { 191 struct sbuf *sb; 192 const u_char *c; 193 size_t len, i; 194 195 /* Trim trailing whitespace. */ 196 len = strlen(label); 197 for (i = len; i > 0; i--) { 198 if (isspace(label[i - 1])) 199 label[i - 1] = '\0'; 200 else 201 break; 202 } 203 if (*label == '\0') 204 return; 205 206 sb = sbuf_new(NULL, NULL, size, SBUF_FIXEDLEN); 207 for (c = label; *c != '\0'; c++) { 208 /* Trim leading whitespace. */ 209 if (isspace(*c) && sbuf_len(sb) == 0) 210 continue; 211 if (!isprint(*c) || isspace(*c) || *c =='"' || *c == '%') 212 sbuf_printf(sb, "%%%02X", *c); 213 else 214 sbuf_putc(sb, *c); 215 } 216 if (sbuf_finish(sb) != 0) 217 label[0] = '\0'; 218 else 219 strlcpy(label, sbuf_data(sb), size); 220 sbuf_delete(sb); 221 } 222 223 static struct g_geom * 224 g_label_create(struct gctl_req *req, struct g_class *mp, struct g_provider *pp, 225 const char *label, const char *dirprefix, off_t mediasize) 226 { 227 struct g_geom *gp; 228 struct g_provider *pp2; 229 struct g_consumer *cp; 230 char name[64]; 231 232 g_topology_assert(); 233 234 if (!g_label_is_name_ok(label)) { 235 G_LABEL_DEBUG(0, "%s contains suspicious label, skipping.", 236 pp->name); 237 G_LABEL_DEBUG(1, "%s suspicious label is: %s", pp->name, label); 238 if (req != NULL) 239 gctl_error(req, "Label name %s is invalid.", label); 240 return (NULL); 241 } 242 gp = NULL; 243 cp = NULL; 244 if (snprintf(name, sizeof(name), "%s%s", dirprefix, label) >= sizeof(name)) { 245 if (req != NULL) 246 gctl_error(req, "Label name %s is too long.", label); 247 return (NULL); 248 } 249 LIST_FOREACH(gp, &mp->geom, geom) { 250 pp2 = LIST_FIRST(&gp->provider); 251 if (pp2 == NULL) 252 continue; 253 if ((pp2->flags & G_PF_ORPHAN) != 0) 254 continue; 255 if (strcmp(pp2->name, name) == 0) { 256 G_LABEL_DEBUG(1, "Label %s(%s) already exists (%s).", 257 label, name, pp->name); 258 if (req != NULL) { 259 gctl_error(req, "Provider %s already exists.", 260 name); 261 } 262 return (NULL); 263 } 264 } 265 gp = g_slice_new(mp, 1, pp, &cp, NULL, 0, NULL); 266 if (gp == NULL) { 267 G_LABEL_DEBUG(0, "Cannot create slice %s.", label); 268 if (req != NULL) 269 gctl_error(req, "Cannot create slice %s.", label); 270 return (NULL); 271 } 272 gp->orphan = g_label_orphan; 273 gp->spoiled = g_label_spoiled; 274 gp->resize = g_label_resize; 275 g_access(cp, -1, 0, 0); 276 g_slice_config(gp, 0, G_SLICE_CONFIG_SET, (off_t)0, mediasize, 277 pp->sectorsize, "%s", name); 278 G_LABEL_DEBUG(1, "Label for provider %s is %s.", pp->name, name); 279 return (gp); 280 } 281 282 static int 283 g_label_destroy(struct g_geom *gp, boolean_t force) 284 { 285 struct g_provider *pp; 286 287 g_topology_assert(); 288 pp = LIST_FIRST(&gp->provider); 289 if (pp != NULL && (pp->acr != 0 || pp->acw != 0 || pp->ace != 0)) { 290 if (force) { 291 G_LABEL_DEBUG(0, "Provider %s is still open, so it " 292 "can't be definitely removed.", pp->name); 293 } else { 294 G_LABEL_DEBUG(1, 295 "Provider %s is still open (r%dw%de%d).", pp->name, 296 pp->acr, pp->acw, pp->ace); 297 return (EBUSY); 298 } 299 } else if (pp != NULL) 300 G_LABEL_DEBUG(1, "Label %s removed.", pp->name); 301 g_slice_spoiled(LIST_FIRST(&gp->consumer)); 302 return (0); 303 } 304 305 static int 306 g_label_read_metadata(struct g_consumer *cp, struct g_label_metadata *md) 307 { 308 struct g_provider *pp; 309 u_char *buf; 310 int error; 311 312 pp = cp->provider; 313 if (pp->sectorsize < sizeof(*md)) 314 return (EINVAL); 315 buf = g_read_data(cp, pp->mediasize - pp->sectorsize, pp->sectorsize, 316 &error); 317 if (buf == NULL) 318 return (error); 319 /* Decode metadata. */ 320 label_metadata_decode(buf, md); 321 g_free(buf); 322 323 return (0); 324 } 325 326 static void 327 g_label_orphan_taste(struct g_consumer *cp __unused) 328 { 329 330 KASSERT(1 == 0, ("%s called?", __func__)); 331 } 332 333 static void 334 g_label_start_taste(struct bio *bp __unused) 335 { 336 337 KASSERT(1 == 0, ("%s called?", __func__)); 338 } 339 340 static int 341 g_label_access_taste(struct g_provider *pp __unused, int dr __unused, 342 int dw __unused, int de __unused) 343 { 344 345 KASSERT(1 == 0, ("%s called", __func__)); 346 return (EOPNOTSUPP); 347 } 348 349 static void 350 g_label_generic_taste(struct g_consumer *cp, char *label, size_t size) 351 { 352 struct g_provider *pp; 353 struct g_label_metadata md; 354 355 g_topology_assert_not(); 356 label[0] = '\0'; 357 pp = cp->provider; 358 359 if (g_label_read_metadata(cp, &md) != 0) 360 return; 361 362 if (strcmp(md.md_magic, G_LABEL_MAGIC) != 0) 363 return; 364 365 if (md.md_version > G_LABEL_VERSION) { 366 printf("geom_label.ko module is too old to handle %s.\n", 367 pp->name); 368 return; 369 } 370 /* 371 * Backward compatibility: there was no md_provsize field in 372 * earlier versions of metadata, so only check if we have it. 373 */ 374 if (md.md_version >= 2 && md.md_provsize != pp->mediasize) 375 return; 376 377 strlcpy(label, md.md_label, size); 378 } 379 380 static struct g_geom * 381 g_label_taste(struct g_class *mp, struct g_provider *pp, int flags __unused) 382 { 383 struct g_consumer *cp; 384 struct g_geom *gp; 385 off_t mediasize; 386 int i; 387 388 g_trace(G_T_TOPOLOGY, "%s(%s, %s)", __func__, mp->name, pp->name); 389 g_topology_assert(); 390 391 G_LABEL_DEBUG(2, "Tasting %s.", pp->name); 392 393 /* Skip providers that are already open for writing. */ 394 if (pp->acw > 0) 395 return (NULL); 396 397 /* Skip broken disks that don't set their sector size */ 398 if (pp->sectorsize == 0) 399 return (NULL); 400 401 if (strcmp(pp->geom->class->name, mp->name) == 0) 402 return (NULL); 403 404 gp = g_new_geomf(mp, "label:taste"); 405 gp->start = g_label_start_taste; 406 gp->access = g_label_access_taste; 407 gp->orphan = g_label_orphan_taste; 408 cp = g_new_consumer(gp); 409 cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE; 410 if (g_attach(cp, pp) != 0) 411 goto end2; 412 if (g_access(cp, 1, 0, 0) != 0) 413 goto end; 414 for (i = 0; g_labels[i] != NULL; i++) { 415 char label[128]; 416 417 if (g_labels[i]->ld_enabled == 0) 418 continue; 419 g_topology_unlock(); 420 g_labels[i]->ld_taste(cp, label, sizeof(label)); 421 g_label_mangle_name(label, sizeof(label)); 422 g_topology_lock(); 423 if (label[0] == '\0') 424 continue; 425 if (g_labels[i] != &g_label_generic) { 426 mediasize = pp->mediasize; 427 } else { 428 mediasize = pp->mediasize - pp->sectorsize; 429 } 430 g_label_create(NULL, mp, pp, label, 431 g_labels[i]->ld_dirprefix, mediasize); 432 } 433 g_access(cp, -1, 0, 0); 434 end: 435 g_detach(cp); 436 end2: 437 g_destroy_consumer(cp); 438 g_destroy_geom(gp); 439 return (NULL); 440 } 441 442 static void 443 g_label_ctl_create(struct gctl_req *req, struct g_class *mp) 444 { 445 struct g_provider *pp; 446 const char *name; 447 int *nargs; 448 449 g_topology_assert(); 450 451 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 452 if (nargs == NULL) { 453 gctl_error(req, "No '%s' argument", "nargs"); 454 return; 455 } 456 if (*nargs != 2) { 457 gctl_error(req, "Invalid number of arguments."); 458 return; 459 } 460 /* 461 * arg1 is the name of provider. 462 */ 463 pp = gctl_get_provider(req, "arg1"); 464 if (pp == NULL) 465 return; 466 /* 467 * arg0 is the label. 468 */ 469 name = gctl_get_asciiparam(req, "arg0"); 470 if (name == NULL) { 471 gctl_error(req, "No 'arg%d' argument", 0); 472 return; 473 } 474 g_label_create(req, mp, pp, name, G_LABEL_DIRPREFIX, pp->mediasize); 475 } 476 477 static const char * 478 g_label_skip_dir(const char *name) 479 { 480 u_int i; 481 482 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0) 483 name += strlen(_PATH_DEV); 484 for (i = 0; g_labels[i] != NULL; i++) { 485 if (strncmp(name, g_labels[i]->ld_dirprefix, 486 strlen(g_labels[i]->ld_dirprefix)) == 0) { 487 name += strlen(g_labels[i]->ld_dirprefix); 488 break; 489 } 490 } 491 return (name); 492 } 493 494 static struct g_geom * 495 g_label_find_geom(struct g_class *mp, const char *name) 496 { 497 struct g_geom *gp; 498 struct g_provider *pp; 499 const char *pname; 500 501 name = g_label_skip_dir(name); 502 LIST_FOREACH(gp, &mp->geom, geom) { 503 pp = LIST_FIRST(&gp->provider); 504 pname = g_label_skip_dir(pp->name); 505 if (strcmp(pname, name) == 0) 506 return (gp); 507 } 508 return (NULL); 509 } 510 511 static void 512 g_label_ctl_destroy(struct gctl_req *req, struct g_class *mp) 513 { 514 int *nargs, *force, error, i; 515 struct g_geom *gp; 516 const char *name; 517 char param[16]; 518 519 g_topology_assert(); 520 521 nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 522 if (nargs == NULL) { 523 gctl_error(req, "No '%s' argument", "nargs"); 524 return; 525 } 526 if (*nargs <= 0) { 527 gctl_error(req, "Missing device(s)."); 528 return; 529 } 530 force = gctl_get_paraml(req, "force", sizeof(*force)); 531 if (force == NULL) { 532 gctl_error(req, "No 'force' argument"); 533 return; 534 } 535 536 for (i = 0; i < *nargs; i++) { 537 snprintf(param, sizeof(param), "arg%d", i); 538 name = gctl_get_asciiparam(req, param); 539 if (name == NULL) { 540 gctl_error(req, "No 'arg%d' argument", i); 541 return; 542 } 543 gp = g_label_find_geom(mp, name); 544 if (gp == NULL) { 545 G_LABEL_DEBUG(1, "Label %s is invalid.", name); 546 gctl_error(req, "Label %s is invalid.", name); 547 return; 548 } 549 error = g_label_destroy(gp, *force); 550 if (error != 0) { 551 gctl_error(req, "Cannot destroy label %s (error=%d).", 552 LIST_FIRST(&gp->provider)->name, error); 553 return; 554 } 555 } 556 } 557 558 static void 559 g_label_config(struct gctl_req *req, struct g_class *mp, const char *verb) 560 { 561 uint32_t *version; 562 563 g_topology_assert(); 564 565 version = gctl_get_paraml(req, "version", sizeof(*version)); 566 if (version == NULL) { 567 gctl_error(req, "No '%s' argument.", "version"); 568 return; 569 } 570 if (*version != G_LABEL_VERSION) { 571 gctl_error(req, "Userland and kernel parts are out of sync."); 572 return; 573 } 574 575 if (strcmp(verb, "create") == 0) { 576 g_label_ctl_create(req, mp); 577 return; 578 } else if (strcmp(verb, "destroy") == 0 || 579 strcmp(verb, "stop") == 0) { 580 g_label_ctl_destroy(req, mp); 581 return; 582 } 583 584 gctl_error(req, "Unknown verb."); 585 } 586 587 DECLARE_GEOM_CLASS(g_label_class, g_label); 588 MODULE_VERSION(geom_label, 0); 589