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