1 /* $NetBSD: libdm_netbsd.c,v 1.8 2019/12/14 09:05:30 mlelstv 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 55 static int dm_list_versions(libdm_task_t, struct dm_ioctl *); 56 static int dm_list_devices(libdm_task_t, struct dm_ioctl *); 57 static int dm_dev_deps(libdm_task_t, struct dm_ioctl *); 58 static int dm_table_status(libdm_task_t, struct dm_ioctl *); 59 60 int 61 nbsd_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 101 struct dm_ioctl* 102 nbsd_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 189 static int 190 dm_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 */ 253 static int 254 dm_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 */ 315 static int 316 dm_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 params = ""; 350 351 plen = strlen(params) + 1; 352 rec_size = sizeof(struct dm_target_spec) + plen; 353 354 /* 355 * In linux when copying table status from kernel next is 356 * number of bytes from the start of the first dm_target_spec 357 * structure. I don't know why but, it has to be done this way. 358 */ 359 next += rec_size; 360 361 if (rec_size > dmi->data_size) { 362 libdm_table_destroy(table); 363 libdm_iter_destroy(iter); 364 return -ENOMEM; 365 } 366 367 dmts->next = next; 368 strlcpy(dmts->target_type, type, DM_MAX_TYPE_NAME); 369 params_start = (char *)dmts + sizeof(struct dm_target_spec); 370 371 strlcpy(params_start, params, plen); 372 373 odmts = dmts; 374 dmts = (struct dm_target_spec *)((uint8_t *)dmts + rec_size); 375 j++; 376 377 libdm_table_destroy(table); 378 } 379 380 if (odmts != NULL) 381 odmts->next = 0; 382 383 libdm_iter_destroy(iter); 384 385 return j; 386 } 387 388 /* 389 * Print dm device dependiences, get minor/major number for 390 * devices. From kernel I will receive major:minor number of 391 * block device used with target. I have to translate it to 392 * raw device numbers and use them, because all other parts of lvm2 393 * uses raw devices internally. 394 */ 395 static int 396 dm_dev_deps(libdm_task_t task, struct dm_ioctl *dmi) 397 { 398 struct dm_target_deps *dmtd; 399 struct kinfo_drivers *kd; 400 401 libdm_cmd_t cmd; 402 libdm_iter_t iter; 403 dev_t dev_deps; 404 405 uint32_t major; 406 size_t val_len, i, j; 407 408 dev_deps = 0; 409 j = 0; 410 i = 0; 411 412 if (sysctlbyname("kern.drivers",NULL,&val_len,NULL,0) < 0) { 413 printf("sysctlbyname failed"); 414 return 0; 415 } 416 417 if ((kd = malloc(val_len)) == NULL){ 418 printf("malloc kd info error\n"); 419 return 0; 420 } 421 422 if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 423 printf("sysctlbyname failed kd"); 424 return 0; 425 } 426 427 dmtd = (struct dm_target_deps *)((uint8_t *)dmi + dmi->data_start); 428 429 if ((cmd = libdm_task_get_cmd(task)) == NULL) 430 return -ENOENT; 431 432 iter = libdm_cmd_iter_create(cmd); 433 434 while((dev_deps = libdm_cmd_get_deps(iter)) != 0) { 435 for (i = 0, val_len /= sizeof(*kd); i < val_len; i++){ 436 if (kd[i].d_bmajor == MAJOR(dev_deps)) { 437 major = kd[i].d_cmajor; 438 break; 439 } 440 } 441 442 dmtd->dev[j] = MKDEV(major, MINOR(dev_deps)); 443 444 j++; 445 } 446 447 dmtd->count = j; 448 449 libdm_iter_destroy(iter); 450 free(kd); 451 452 return j; 453 } 454