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