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