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