1 /* $NetBSD: libdm_netbsd.c,v 1.3 2009/06/09 18:29:09 haad Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Adam Hamsik. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 #include <sys/ioctl.h> 34 #include <sys/types.h> 35 #include <sys/sysctl.h> 36 37 #include <err.h> 38 #include <errno.h> 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <unistd.h> 44 45 #include <netbsd-dm.h> 46 47 #include <dm-ioctl.h> 48 49 #include "lib.h" 50 51 struct nbsd_dm_target_param { 52 char *name; 53 prop_dictionary_t (*parse)(char *); 54 }; 55 56 #define DMI_SIZE 16 * 1024 57 58 static int dm_list_versions(prop_dictionary_t, struct dm_ioctl *); 59 static int dm_list_devices(prop_dictionary_t, struct dm_ioctl *); 60 static int dm_dev_deps(prop_dictionary_t, struct dm_ioctl *); 61 static int dm_table_status(prop_dictionary_t, struct dm_ioctl *); 62 63 static prop_dictionary_t dm_parse_linear(char *); 64 static prop_dictionary_t dm_parse_stripe(char *); 65 static prop_dictionary_t dm_parse_mirror(char *); 66 static prop_dictionary_t dm_parse_snapshot(char *); 67 static prop_dictionary_t dm_parse_snapshot_origin(char *); 68 static prop_dictionary_t dm_parse_default(char *); 69 70 static struct nbsd_dm_target_param dmt_parse[] = { 71 {"linear", dm_parse_linear}, 72 {"striped", dm_parse_stripe}, 73 {"mirror", dm_parse_mirror}, 74 {"snapshot", dm_parse_snapshot}, 75 {"snapshot-origin", dm_parse_snapshot_origin}, 76 {NULL, NULL}, 77 }; 78 79 /* 80 * Parse params string to target specific proplib dictionary. 81 * 82 * <key>params</key> 83 * <dict> 84 * <key>device</key> 85 * <array> 86 * <dict> 87 * <key>device</key> 88 * <string>/dev/wd1a</string> 89 * <key>offset</key> 90 * <integer>0x384</integer> 91 * </dict> 92 * </array> 93 * <!-- Other target config stuff --> 94 * </dict> 95 * 96 */ 97 prop_dictionary_t 98 nbsd_dm_parse_param(const char *target, const char *params) 99 { 100 int i; 101 size_t slen, dlen; 102 prop_dictionary_t dict; 103 char *param; 104 105 dict = NULL; 106 slen = strlen(target); 107 108 /* copy parameter string to new buffer */ 109 param = dm_malloc(strlen(params) * sizeof(char)); 110 strlcpy(param, params, strlen(params)+1); 111 112 for(i = 0; dmt_parse[i].name != NULL; i++) { 113 dlen = strlen(dmt_parse[i].name); 114 115 if (slen != dlen) 116 continue; 117 118 if (strncmp(target, dmt_parse[i].name, slen) == 0) 119 break; 120 } 121 122 /* Create default dictionary with key params and with string as a value */ 123 if (dmt_parse[i].name == NULL) 124 dm_parse_default(param); 125 126 dict = dmt_parse[i].parse(param); 127 128 dm_free(param); 129 130 return dict; 131 } 132 133 /* 134 * Example line sent to dm from lvm tools when using linear target. 135 * start length linear device1 offset1 136 * 0 65536 linear /dev/hda 0 137 */ 138 static prop_dictionary_t 139 dm_parse_linear(char *params) 140 { 141 prop_dictionary_t dict; 142 char **ap, *argv[3]; 143 144 dict = prop_dictionary_create(); 145 146 if (params == NULL) 147 return dict; 148 149 /* 150 * Parse a string, containing tokens delimited by white space, 151 * into an argument vector 152 */ 153 for (ap = argv; ap < &argv[2] && 154 (*ap = strsep(¶ms, " \t")) != NULL;) { 155 if (**ap != '\0') 156 ap++; 157 } 158 159 prop_dictionary_set_cstring(dict, DM_TARGET_LINEAR_DEVICE, argv[0]); 160 prop_dictionary_set_uint64(dict, DM_TARGET_LINEAR_OFFSET, strtoll(argv[1], (char **)NULL, 10)); 161 162 return dict; 163 } 164 165 /* 166 * Example line sent to dm from lvm tools when using striped target. 167 * start length striped #stripes chunk_size device1 offset1 ... deviceN offsetN 168 * 0 65536 striped 2 512 /dev/hda 0 /dev/hdb 0 169 */ 170 static prop_dictionary_t 171 dm_parse_stripe(char *params) 172 { 173 prop_dictionary_t dict, dev_dict; 174 prop_array_t dev_array; 175 char **ap, *argv[10]; /* Limit number of disk stripes to 10 */ 176 177 dict = prop_dictionary_create(); 178 179 if (params == NULL) 180 return dict; 181 182 /* 183 * Parse a string, containing tokens delimited by white space, 184 * into an argument vector 185 */ 186 for (ap = argv; ap < &argv[9] && 187 (*ap = strsep(¶ms, " \t")) != NULL;) { 188 if (**ap != '\0') 189 ap++; 190 } 191 192 prop_dictionary_set_uint64(dict, DM_TARGET_STRIPE_STRIPES, 193 strtol(argv[0], (char **)NULL, 10)); 194 prop_dictionary_set_uint64(dict, DM_TARGET_STRIPE_CHUNKSIZE, 195 strtol(argv[1], (char **)NULL, 10)); 196 197 dev_array = prop_array_create(); 198 199 dev_dict = prop_dictionary_create(); 200 prop_dictionary_set_cstring(dev_dict, DM_TARGET_STRIPE_DEVICE, argv[2]); 201 prop_dictionary_set_uint64(dev_dict, DM_TARGET_STRIPE_OFFSET, 202 strtol(argv[3], (char **)NULL, 10)); 203 204 prop_array_add(dev_array, dev_dict); 205 prop_object_release(dev_dict); 206 207 dev_dict = prop_dictionary_create(); 208 prop_dictionary_set_cstring(dev_dict, DM_TARGET_STRIPE_DEVICE, argv[4]); 209 prop_dictionary_set_uint64(dev_dict, DM_TARGET_STRIPE_OFFSET, 210 strtol(argv[5], (char **)NULL, 10)); 211 212 prop_array_add(dev_array, dev_dict); 213 prop_object_release(dev_dict); 214 215 prop_dictionary_set(dict, DM_TARGET_STRIPE_DEVARRAY, dev_array); 216 prop_object_release(dev_array); 217 218 return dict; 219 } 220 221 static prop_dictionary_t 222 dm_parse_mirror(char *params) 223 { 224 prop_dictionary_t dict; 225 226 dict = prop_dictionary_create(); 227 228 return dict; 229 } 230 231 static prop_dictionary_t 232 dm_parse_snapshot(char *params) 233 { 234 prop_dictionary_t dict; 235 236 dict = prop_dictionary_create(); 237 238 return dict; 239 } 240 241 static prop_dictionary_t 242 dm_parse_snapshot_origin(char *params) 243 { 244 prop_dictionary_t dict; 245 246 dict = prop_dictionary_create(); 247 248 return dict; 249 } 250 251 static prop_dictionary_t 252 dm_parse_default(char *params) 253 { 254 prop_dictionary_t dict; 255 256 dict = prop_dictionary_create(); 257 258 prop_dictionary_set_cstring(dict, DM_TABLE_PARAMS, params); 259 260 return dict; 261 } 262 263 int 264 nbsd_get_dm_major(uint32_t *major, int type) 265 { 266 size_t val_len,i; 267 struct kinfo_drivers *kd; 268 269 if (sysctlbyname("kern.drivers",NULL,&val_len,NULL,0) < 0) { 270 printf("sysctlbyname failed"); 271 return 0; 272 } 273 274 if ((kd = malloc (val_len)) == NULL){ 275 printf("malloc kd info error\n"); 276 return 0; 277 } 278 279 if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 280 printf("sysctlbyname failed kd"); 281 return 0; 282 } 283 284 for (i = 0, val_len /= sizeof(*kd); i < val_len; i++) { 285 286 if (strncmp(kd[i].d_name,DM_NAME,strlen(kd[i].d_name)) == 0){ 287 288 if (type == DM_CHAR_MAJOR) 289 /* Set major to dm-driver char major number. */ 290 *major = kd[i].d_cmajor; 291 else 292 if (type == DM_BLOCK_MAJOR) 293 *major = kd[i].d_bmajor; 294 295 free(kd); 296 297 return 1; 298 } 299 } 300 301 free(kd); 302 303 return 0; 304 } 305 306 int 307 nbsd_dmi_add_version(const int *version, prop_dictionary_t dm_dict) 308 { 309 prop_array_t ver; 310 size_t i; 311 312 if ((ver = prop_array_create()) == NULL) 313 return -1; 314 315 for (i=0;i<3;i++) 316 prop_array_set_uint32(ver,i,version[i]); 317 318 if ((prop_dictionary_set(dm_dict,"version",ver)) == false) 319 return -1; 320 321 prop_object_release(ver); 322 323 return 0; 324 } 325 326 struct dm_ioctl* 327 nbsd_dm_dict_to_dmi(prop_dictionary_t dm_dict,const int cmd) 328 { 329 struct dm_ioctl *dmi; 330 prop_array_t ver; 331 332 size_t i; 333 int r; 334 char *name, *uuid; 335 uint32_t major,minor; 336 337 name = NULL; 338 uuid = NULL; 339 minor = 0; 340 341 nbsd_get_dm_major(&major, DM_BLOCK_MAJOR); 342 343 if (!(dmi = dm_malloc(DMI_SIZE))) 344 return NULL; 345 346 memset(dmi,0,DMI_SIZE); 347 348 prop_dictionary_get_int32(dm_dict, DM_IOCTL_OPEN, &dmi->open_count); 349 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_EVENT, &dmi->event_nr); 350 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &dmi->flags); 351 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, 352 &dmi->target_count); 353 354 if (prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor)) 355 dmi->dev = MKDEV(major, minor); 356 else 357 dmi->dev = 0; 358 359 /* Copy name and uuid to dm_ioctl. */ 360 if (prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, 361 (const char **)&name)){ 362 strlcpy(dmi->name, name, DM_NAME_LEN); 363 } else 364 dmi->name[0] = '\0'; 365 366 if (prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, 367 (const char **)&uuid)){ 368 strlcpy(dmi->uuid, uuid, DM_UUID_LEN); 369 } else 370 dmi->uuid[0] = '\0'; 371 372 /* dmi parsing values, size of dmi block and offset to data. */ 373 dmi->data_size = DMI_SIZE; 374 dmi->data_start = sizeof(struct dm_ioctl); 375 376 /* Get kernel version from dm_dict. */ 377 ver = prop_dictionary_get(dm_dict,DM_IOCTL_VERSION); 378 379 for(i=0; i<3; i++) 380 prop_array_get_uint32(ver,i,&dmi->version[i]); 381 382 switch (cmd){ 383 384 case DM_LIST_VERSIONS: 385 r = dm_list_versions(dm_dict,dmi); 386 if (r >= 0) 387 dmi->target_count = r; 388 break; 389 390 case DM_LIST_DEVICES: 391 r = dm_list_devices(dm_dict,dmi); 392 if (r >= 0) 393 dmi->target_count = r; 394 break; 395 396 case DM_TABLE_STATUS: 397 r = dm_table_status(dm_dict,dmi); 398 if (r >= 0) 399 dmi->target_count = r; 400 break; 401 402 case DM_TABLE_DEPS: 403 r = dm_dev_deps(dm_dict,dmi); 404 if (r >= 0) 405 dmi->target_count = r; 406 break; 407 } 408 409 return dmi; 410 } 411 412 /* 413 * Parse dm_dict when targets command was called and fill dm_ioctl buffer with it. 414 * 415 * Return number of targets or if failed <0 error. 416 */ 417 418 static int 419 dm_list_versions(prop_dictionary_t dm_dict, struct dm_ioctl *dmi) 420 { 421 struct dm_target_versions *dmtv,*odmtv; 422 423 prop_array_t targets,ver; 424 prop_dictionary_t target_dict; 425 prop_object_iterator_t iter; 426 427 char *name; 428 size_t j,i,slen,rec_size; 429 430 odmtv = NULL; 431 name = NULL; 432 j = 0; 433 434 dmtv = (struct dm_target_versions *)((uint8_t *)dmi + dmi->data_start); 435 436 /* printf("dmi: vers: %d.%d.%d data_size: %d data_start: %d name: %s t_count: %d\n", 437 dmi->version[0],dmi->version[1],dmi->version[2],dmi->data_size,dmi->data_start, 438 dmi->name,dmi->target_count); 439 440 printf("dmi: size: %d -- %p --- %p \n",sizeof(struct dm_ioctl),dmi,dmi+dmi->data_start); 441 printf("dmtv: size: %p --- %p\n",dmtv,(struct dm_target_versions *)(dmi+312));*/ 442 443 /* get prop_array of target_version dictionaries */ 444 if ((targets = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA))){ 445 446 iter = prop_array_iterator(targets); 447 if (!iter) 448 err(EXIT_FAILURE,"dm_list_versions %s",__func__); 449 450 while((target_dict = prop_object_iterator_next(iter)) != NULL){ 451 j++; 452 453 prop_dictionary_get_cstring_nocopy(target_dict, 454 DM_TARGETS_NAME,(const char **)&name); 455 456 slen = strlen(name) + 1; 457 rec_size = sizeof(struct dm_target_versions) + slen + 1; 458 459 if (rec_size > dmi->data_size) 460 return -ENOMEM; 461 462 ver = prop_dictionary_get(target_dict,DM_TARGETS_VERSION); 463 464 for (i=0; i<3; i++) 465 prop_array_get_uint32(ver,i,&dmtv->version[i]); 466 467 dmtv->next = rec_size; 468 469 strlcpy(dmtv->name,name,slen); 470 471 odmtv = dmtv; 472 473 dmtv =(struct dm_target_versions *)((uint8_t *)dmtv + rec_size); 474 } 475 476 if (odmtv != NULL) 477 odmtv->next = 0; 478 } 479 480 prop_object_iterator_release(iter); 481 return j; 482 } 483 484 /* 485 * List all available dm devices in system. 486 */ 487 static int 488 dm_list_devices(prop_dictionary_t dm_dict, struct dm_ioctl *dmi) 489 { 490 struct dm_name_list *dml,*odml; 491 492 prop_array_t targets; 493 prop_dictionary_t target_dict; 494 prop_object_iterator_t iter; 495 496 uint32_t minor; 497 uint32_t major; 498 499 char *name; 500 size_t j,slen,rec_size; 501 502 odml = NULL; 503 name = NULL; 504 minor = 0; 505 j = 0; 506 507 nbsd_get_dm_major(&major,DM_BLOCK_MAJOR); 508 509 dml = (struct dm_name_list *)((uint8_t *)dmi + dmi->data_start); 510 511 if ((targets = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA))){ 512 513 iter = prop_array_iterator(targets); 514 if (!iter) 515 err(EXIT_FAILURE,"dm_list_devices %s",__func__); 516 517 while((target_dict = prop_object_iterator_next(iter)) != NULL){ 518 519 prop_dictionary_get_cstring_nocopy(target_dict, 520 DM_DEV_NAME,(const char **)&name); 521 522 prop_dictionary_get_uint32(target_dict,DM_DEV_DEV,&minor); 523 524 dml->dev = MKDEV(major,minor); 525 526 slen = strlen(name) + 1; 527 rec_size = sizeof(struct dm_name_list) + slen + 1; 528 529 if (rec_size > dmi->data_size) 530 return -ENOMEM; 531 532 dml->next = rec_size; 533 534 strlcpy(dml->name,name,slen); 535 536 odml = dml; 537 538 dml =(struct dm_name_list *)((uint8_t *)dml + rec_size); 539 540 j++; 541 } 542 543 if (odml != NULL) 544 odml->next = 0; 545 } 546 prop_object_iterator_release(iter); 547 return j; 548 } 549 550 /* 551 * Print status of each table, target arguments, start sector, 552 * size and target name. 553 */ 554 static int 555 dm_table_status(prop_dictionary_t dm_dict,struct dm_ioctl *dmi) 556 { 557 struct dm_target_spec *dmts, *odmts; 558 559 prop_array_t targets; 560 prop_dictionary_t target_dict; 561 prop_object_iterator_t iter; 562 563 char *type,*params,*params_start; 564 565 bool prm; 566 size_t j,plen,rec_size,next; 567 568 j = 0; 569 next = 0; 570 params = NULL; 571 odmts = NULL; 572 rec_size = 0; 573 plen = -1; 574 prm = false; 575 576 dmts = (struct dm_target_spec *)((uint8_t *)dmi + dmi->data_start); 577 578 if ((targets = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA))){ 579 580 iter = prop_array_iterator(targets); 581 if (!iter) 582 err(EXIT_FAILURE,"dm_table_status %s",__func__); 583 584 while((target_dict = prop_object_iterator_next(iter)) != NULL){ 585 586 prop_dictionary_get_cstring_nocopy(target_dict, 587 DM_TABLE_TYPE,(const char **)&type); 588 589 prm = prop_dictionary_get_cstring_nocopy(target_dict, 590 DM_TABLE_PARAMS,(const char **)¶ms); 591 592 prop_dictionary_get_uint64(target_dict,DM_TABLE_START,&dmts->sector_start); 593 prop_dictionary_get_uint64(target_dict,DM_TABLE_LENGTH,&dmts->length); 594 prop_dictionary_get_int32(target_dict,DM_TABLE_STAT,&dmts->status); 595 596 if (prm) 597 plen = strlen(params) + 1; 598 599 rec_size = sizeof(struct dm_target_spec) + plen; 600 601 /* 602 * In linux when copying table status from kernel next is 603 * number of bytes from the start of the first dm_target_spec 604 * structure. I don't know why but, it has to be done this way. 605 */ 606 next += rec_size; 607 608 if (rec_size > dmi->data_size) 609 return -ENOMEM; 610 611 dmts->next = next; 612 613 strlcpy(dmts->target_type, type, DM_MAX_TYPE_NAME); 614 615 params_start = (char *)dmts + sizeof(struct dm_target_spec); 616 617 if (prm) 618 strlcpy(params_start, params, plen); 619 else 620 params_start = "\0"; 621 622 623 odmts = dmts; 624 625 dmts = (struct dm_target_spec *)((uint8_t *)dmts + rec_size); 626 627 j++; 628 629 } 630 631 if (odmts != NULL) 632 odmts->next = 0; 633 } 634 prop_object_iterator_release(iter); 635 636 return j; 637 } 638 639 /* 640 * Print dm device dependiences, get minor/major number for 641 * devices. From kernel I will receive major:minor number of 642 * block device used with target. I have to translate it to 643 * raw device numbers and use them, because all other parts of lvm2 644 * uses raw devices internaly. 645 */ 646 static int 647 dm_dev_deps(prop_dictionary_t dm_dict, struct dm_ioctl *dmi) 648 { 649 struct dm_target_deps *dmtd; 650 struct kinfo_drivers *kd; 651 652 prop_array_t targets; 653 prop_object_iterator_t iter; 654 655 uint32_t major; 656 657 size_t val_len, i, j; 658 659 uint64_t dev_tmp; 660 661 dev_tmp = 0; 662 j = 0; 663 i = 0; 664 665 if (sysctlbyname("kern.drivers",NULL,&val_len,NULL,0) < 0) { 666 printf("sysctlbyname failed"); 667 return 0; 668 } 669 670 if ((kd = malloc (val_len)) == NULL){ 671 printf("malloc kd info error\n"); 672 return 0; 673 } 674 675 if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 676 printf("sysctlbyname failed kd"); 677 return 0; 678 } 679 680 dmtd = (struct dm_target_deps *)((uint8_t *)dmi + dmi->data_start); 681 682 if ((targets = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA))){ 683 684 iter = prop_array_iterator(targets); 685 if (!iter) 686 err(EXIT_FAILURE,"dm_target_deps %s", __func__); 687 688 while((prop_object_iterator_next(iter)) != NULL){ 689 690 prop_array_get_uint64(targets, j, &dev_tmp); 691 692 for (i = 0, val_len /= sizeof(*kd); i < val_len; i++){ 693 if (kd[i].d_bmajor == MAJOR(dev_tmp)) { 694 major = kd[i].d_cmajor; 695 break; 696 } 697 } 698 699 dmtd->dev[j] = MKDEV(major,MINOR(dev_tmp)); 700 701 j++; 702 } 703 } 704 705 dmtd->count = j; 706 707 prop_object_iterator_release(iter); 708 709 return j; 710 } 711