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