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