1 /* $NetBSD: libdm_netbsd.c,v 1.1 2008/12/22 00:56:59 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 <unistd.h> 43 44 #include <netbsd-dm.h> 45 46 #include <dm-ioctl.h> 47 48 #include "lib.h" 49 50 #define DMI_SIZE 16 * 1024 51 52 static int dm_list_versions(prop_dictionary_t, struct dm_ioctl *); 53 static int dm_list_devices(prop_dictionary_t, struct dm_ioctl *); 54 static int dm_dev_deps(prop_dictionary_t, struct dm_ioctl *); 55 static int dm_table_status(prop_dictionary_t, struct dm_ioctl *); 56 57 int 58 nbsd_get_dm_major(uint32_t *major, int type) 59 { 60 size_t val_len,i; 61 struct kinfo_drivers *kd; 62 63 if (sysctlbyname("kern.drivers",NULL,&val_len,NULL,0) < 0) { 64 printf("sysctlbyname failed"); 65 return 0; 66 } 67 68 if ((kd = malloc (val_len)) == NULL){ 69 printf("malloc kd info error\n"); 70 return 0; 71 } 72 73 if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 74 printf("sysctlbyname failed kd"); 75 return 0; 76 } 77 78 for (i = 0, val_len /= sizeof(*kd); i < val_len; i++) { 79 80 if (strncmp(kd[i].d_name,DM_NAME,strlen(kd[i].d_name)) == 0){ 81 82 if (type == DM_CHAR_MAJOR) 83 /* Set major to dm-driver char major number. */ 84 *major = kd[i].d_cmajor; 85 else 86 if (type == DM_BLOCK_MAJOR) 87 *major = kd[i].d_bmajor; 88 89 free(kd); 90 91 return 1; 92 } 93 } 94 95 free(kd); 96 97 return 0; 98 } 99 100 int 101 nbsd_dmi_add_version(const int *version, prop_dictionary_t dm_dict) 102 { 103 prop_array_t ver; 104 size_t i; 105 106 if ((ver = prop_array_create()) == NULL) 107 return -1; 108 109 for (i=0;i<3;i++) 110 prop_array_set_uint32(ver,i,version[i]); 111 112 if ((prop_dictionary_set(dm_dict,"version",ver)) == false) 113 return -1; 114 115 prop_object_release(ver); 116 117 return 0; 118 } 119 120 struct dm_ioctl* 121 nbsd_dm_dict_to_dmi(prop_dictionary_t dm_dict,const int cmd) 122 { 123 struct dm_ioctl *dmi; 124 prop_array_t ver; 125 126 size_t i; 127 int r; 128 char *name, *uuid; 129 uint32_t major,minor; 130 131 name = NULL; 132 uuid = NULL; 133 minor = 0; 134 135 nbsd_get_dm_major(&major, DM_BLOCK_MAJOR); 136 137 if (!(dmi = dm_malloc(DMI_SIZE))) 138 return NULL; 139 140 memset(dmi,0,DMI_SIZE); 141 142 prop_dictionary_get_int32(dm_dict, DM_IOCTL_OPEN, &dmi->open_count); 143 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_EVENT, &dmi->event_nr); 144 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_FLAGS, &dmi->flags); 145 prop_dictionary_get_uint32(dm_dict, DM_IOCTL_TARGET_COUNT, 146 &dmi->target_count); 147 148 if (prop_dictionary_get_uint32(dm_dict, DM_IOCTL_MINOR, &minor)) 149 dmi->dev = MKDEV(major, minor); 150 else 151 dmi->dev = 0; 152 153 /* Copy name and uuid to dm_ioctl. */ 154 if (prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_NAME, 155 (const char **)&name)){ 156 strlcpy(dmi->name, name, DM_NAME_LEN); 157 } else 158 dmi->name[0] = '\0'; 159 160 if (prop_dictionary_get_cstring_nocopy(dm_dict, DM_IOCTL_UUID, 161 (const char **)&uuid)){ 162 strlcpy(dmi->uuid, uuid, DM_UUID_LEN); 163 } else 164 dmi->uuid[0] = '\0'; 165 166 /* dmi parsing values, size of dmi block and offset to data. */ 167 dmi->data_size = DMI_SIZE; 168 dmi->data_start = sizeof(struct dm_ioctl); 169 170 /* Get kernel version from dm_dict. */ 171 ver = prop_dictionary_get(dm_dict,DM_IOCTL_VERSION); 172 173 for(i=0; i<3; i++) 174 prop_array_get_uint32(ver,i,&dmi->version[i]); 175 176 switch (cmd){ 177 178 case DM_LIST_VERSIONS: 179 r = dm_list_versions(dm_dict,dmi); 180 if (r >= 0) 181 dmi->target_count = r; 182 break; 183 184 case DM_LIST_DEVICES: 185 r = dm_list_devices(dm_dict,dmi); 186 if (r >= 0) 187 dmi->target_count = r; 188 break; 189 190 case DM_TABLE_STATUS: 191 r = dm_table_status(dm_dict,dmi); 192 if (r >= 0) 193 dmi->target_count = r; 194 break; 195 196 case DM_TABLE_DEPS: 197 r = dm_dev_deps(dm_dict,dmi); 198 if (r >= 0) 199 dmi->target_count = r; 200 break; 201 } 202 203 return dmi; 204 } 205 206 /* 207 * Parse dm_dict when targets command was called and fill dm_ioctl buffer with it. 208 * 209 * Return number of targets or if failed <0 error. 210 */ 211 212 static int 213 dm_list_versions(prop_dictionary_t dm_dict, struct dm_ioctl *dmi) 214 { 215 struct dm_target_versions *dmtv,*odmtv; 216 217 prop_array_t targets,ver; 218 prop_dictionary_t target_dict; 219 prop_object_iterator_t iter; 220 221 char *name; 222 size_t j,i,slen,rec_size; 223 224 odmtv = NULL; 225 name = NULL; 226 j = 0; 227 228 dmtv = (struct dm_target_versions *)((uint8_t *)dmi + dmi->data_start); 229 230 /* printf("dmi: vers: %d.%d.%d data_size: %d data_start: %d name: %s t_count: %d\n", 231 dmi->version[0],dmi->version[1],dmi->version[2],dmi->data_size,dmi->data_start, 232 dmi->name,dmi->target_count); 233 234 printf("dmi: size: %d -- %p --- %p \n",sizeof(struct dm_ioctl),dmi,dmi+dmi->data_start); 235 printf("dmtv: size: %p --- %p\n",dmtv,(struct dm_target_versions *)(dmi+312));*/ 236 237 /* get prop_array of target_version dictionaries */ 238 if ((targets = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA))){ 239 240 iter = prop_array_iterator(targets); 241 if (!iter) 242 err(EXIT_FAILURE,"dm_list_versions %s",__func__); 243 244 while((target_dict = prop_object_iterator_next(iter)) != NULL){ 245 j++; 246 247 prop_dictionary_get_cstring_nocopy(target_dict, 248 DM_TARGETS_NAME,(const char **)&name); 249 250 slen = strlen(name) + 1; 251 rec_size = sizeof(struct dm_target_versions) + slen + 1; 252 253 if (rec_size > dmi->data_size) 254 return -ENOMEM; 255 256 ver = prop_dictionary_get(target_dict,DM_TARGETS_VERSION); 257 258 for (i=0; i<3; i++) 259 prop_array_get_uint32(ver,i,&dmtv->version[i]); 260 261 dmtv->next = rec_size; 262 263 strlcpy(dmtv->name,name,slen); 264 265 odmtv = dmtv; 266 267 dmtv =(struct dm_target_versions *)((uint8_t *)dmtv + rec_size); 268 } 269 270 if (odmtv != NULL) 271 odmtv->next = 0; 272 } 273 274 prop_object_iterator_release(iter); 275 return j; 276 } 277 278 /* 279 * List all available dm devices in system. 280 */ 281 static int 282 dm_list_devices(prop_dictionary_t dm_dict, struct dm_ioctl *dmi) 283 { 284 struct dm_name_list *dml,*odml; 285 286 prop_array_t targets; 287 prop_dictionary_t target_dict; 288 prop_object_iterator_t iter; 289 290 uint32_t minor; 291 uint32_t major; 292 293 char *name; 294 size_t j,slen,rec_size; 295 296 odml = NULL; 297 name = NULL; 298 minor = 0; 299 j = 0; 300 301 nbsd_get_dm_major(&major,DM_BLOCK_MAJOR); 302 303 dml = (struct dm_name_list *)((uint8_t *)dmi + dmi->data_start); 304 305 if ((targets = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA))){ 306 307 iter = prop_array_iterator(targets); 308 if (!iter) 309 err(EXIT_FAILURE,"dm_list_devices %s",__func__); 310 311 while((target_dict = prop_object_iterator_next(iter)) != NULL){ 312 313 prop_dictionary_get_cstring_nocopy(target_dict, 314 DM_DEV_NAME,(const char **)&name); 315 316 prop_dictionary_get_uint32(target_dict,DM_DEV_DEV,&minor); 317 318 dml->dev = MKDEV(major,minor); 319 320 slen = strlen(name) + 1; 321 rec_size = sizeof(struct dm_name_list) + slen + 1; 322 323 if (rec_size > dmi->data_size) 324 return -ENOMEM; 325 326 dml->next = rec_size; 327 328 strlcpy(dml->name,name,slen); 329 330 odml = dml; 331 332 dml =(struct dm_name_list *)((uint8_t *)dml + rec_size); 333 334 j++; 335 } 336 337 if (odml != NULL) 338 odml->next = 0; 339 } 340 prop_object_iterator_release(iter); 341 return j; 342 } 343 344 /* 345 * Print status of each table, target arguments, start sector, 346 * size and target name. 347 */ 348 static int 349 dm_table_status(prop_dictionary_t dm_dict,struct dm_ioctl *dmi) 350 { 351 struct dm_target_spec *dmts, *odmts; 352 353 prop_array_t targets; 354 prop_dictionary_t target_dict; 355 prop_object_iterator_t iter; 356 357 char *type,*params,*params_start; 358 359 bool prm; 360 size_t j,plen,rec_size,next; 361 362 j = 0; 363 next = 0; 364 params = NULL; 365 odmts = NULL; 366 rec_size = 0; 367 plen = -1; 368 prm = false; 369 370 dmts = (struct dm_target_spec *)((uint8_t *)dmi + dmi->data_start); 371 372 if ((targets = prop_dictionary_get(dm_dict,DM_IOCTL_CMD_DATA))){ 373 374 iter = prop_array_iterator(targets); 375 if (!iter) 376 err(EXIT_FAILURE,"dm_table_status %s",__func__); 377 378 while((target_dict = prop_object_iterator_next(iter)) != NULL){ 379 380 prop_dictionary_get_cstring_nocopy(target_dict, 381 DM_TABLE_TYPE,(const char **)&type); 382 383 prm = prop_dictionary_get_cstring_nocopy(target_dict, 384 DM_TABLE_PARAMS,(const char **)¶ms); 385 386 prop_dictionary_get_uint64(target_dict,DM_TABLE_START,&dmts->sector_start); 387 prop_dictionary_get_uint64(target_dict,DM_TABLE_LENGTH,&dmts->length); 388 prop_dictionary_get_int32(target_dict,DM_TABLE_STAT,&dmts->status); 389 390 if (prm) 391 plen = strlen(params) + 1; 392 393 rec_size = sizeof(struct dm_target_spec) + plen; 394 395 /* 396 * In linux when copying table status from kernel next is 397 * number of bytes from the start of the first dm_target_spec 398 * structure. I don't know why but, it has to be done this way. 399 */ 400 next += rec_size; 401 402 if (rec_size > dmi->data_size) 403 return -ENOMEM; 404 405 dmts->next = next; 406 407 strlcpy(dmts->target_type, type, DM_MAX_TYPE_NAME); 408 409 params_start = (char *)dmts + sizeof(struct dm_target_spec); 410 411 if (prm) 412 strlcpy(params_start, params, plen); 413 else 414 params_start = "\0"; 415 416 417 odmts = dmts; 418 419 dmts = (struct dm_target_spec *)((uint8_t *)dmts + rec_size); 420 421 j++; 422 423 } 424 425 if (odmts != NULL) 426 odmts->next = 0; 427 } 428 prop_object_iterator_release(iter); 429 430 return j; 431 } 432 433 /* 434 * Print dm device dependiences, get minor/major number for 435 * devices. From kernel I will receive major:minor number of 436 * block device used with target. I have to translate it to 437 * raw device numbers and use them, because all other parts of lvm2 438 * uses raw devices internaly. 439 */ 440 static int 441 dm_dev_deps(prop_dictionary_t dm_dict, struct dm_ioctl *dmi) 442 { 443 struct dm_target_deps *dmtd; 444 struct kinfo_drivers *kd; 445 446 prop_array_t targets; 447 prop_object_iterator_t iter; 448 449 uint32_t major; 450 451 size_t val_len, i, j; 452 453 uint64_t dev_tmp; 454 455 dev_tmp = 0; 456 j = 0; 457 i = 0; 458 459 if (sysctlbyname("kern.drivers",NULL,&val_len,NULL,0) < 0) { 460 printf("sysctlbyname failed"); 461 return 0; 462 } 463 464 if ((kd = malloc (val_len)) == NULL){ 465 printf("malloc kd info error\n"); 466 return 0; 467 } 468 469 if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 470 printf("sysctlbyname failed kd"); 471 return 0; 472 } 473 474 dmtd = (struct dm_target_deps *)((uint8_t *)dmi + dmi->data_start); 475 476 if ((targets = prop_dictionary_get(dm_dict, DM_IOCTL_CMD_DATA))){ 477 478 iter = prop_array_iterator(targets); 479 if (!iter) 480 err(EXIT_FAILURE,"dm_target_deps %s", __func__); 481 482 while((prop_object_iterator_next(iter)) != NULL){ 483 484 prop_array_get_uint64(targets, j, &dev_tmp); 485 486 for (i = 0, val_len /= sizeof(*kd); i < val_len; i++){ 487 if (kd[i].d_bmajor == MAJOR(dev_tmp)) { 488 major = kd[i].d_cmajor; 489 break; 490 } 491 } 492 493 dmtd->dev[j] = MKDEV(major,MINOR(dev_tmp)); 494 495 j++; 496 } 497 } 498 499 dmtd->count = j; 500 501 prop_object_iterator_release(iter); 502 503 return j; 504 } 505