1 1.8 mlelstv /* $NetBSD: libdm_netbsd.c,v 1.8 2019/12/14 09:05:30 mlelstv Exp $ */ 2 1.1 haad 3 1.1 haad /* 4 1.1 haad * Copyright (c) 1996, 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc. 5 1.1 haad * All rights reserved. 6 1.1 haad * 7 1.1 haad * This code is derived from software contributed to The NetBSD Foundation 8 1.1 haad * by Adam Hamsik. 9 1.1 haad * 10 1.1 haad * Redistribution and use in source and binary forms, with or without 11 1.1 haad * modification, are permitted provided that the following conditions 12 1.1 haad * are met: 13 1.1 haad * 1. Redistributions of source code must retain the above copyright 14 1.1 haad * notice, this list of conditions and the following disclaimer. 15 1.1 haad * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 haad * notice, this list of conditions and the following disclaimer in the 17 1.1 haad * documentation and/or other materials provided with the distribution. 18 1.1 haad * 19 1.1 haad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 haad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 haad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 haad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 haad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 haad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 haad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 haad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 haad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 haad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 haad * POSSIBILITY OF SUCH DAMAGE. 30 1.1 haad */ 31 1.1 haad 32 1.1 haad 33 1.1 haad #include <sys/ioctl.h> 34 1.1 haad #include <sys/types.h> 35 1.1 haad #include <sys/sysctl.h> 36 1.1 haad 37 1.1 haad #include <err.h> 38 1.1 haad #include <errno.h> 39 1.1 haad 40 1.1 haad #include <stdio.h> 41 1.1 haad #include <stdlib.h> 42 1.1 haad #include <unistd.h> 43 1.6 christos #include <stdbool.h> 44 1.1 haad 45 1.7 haad #include <dm.h> 46 1.5 haad #include <dev/dm/netbsd-dm.h> 47 1.1 haad 48 1.1 haad #include <dm-ioctl.h> 49 1.1 haad 50 1.1 haad #include "lib.h" 51 1.5 haad #include "libdm-netbsd.h" 52 1.1 haad 53 1.1 haad #define DMI_SIZE 16 * 1024 54 1.1 haad 55 1.7 haad static int dm_list_versions(libdm_task_t, struct dm_ioctl *); 56 1.7 haad static int dm_list_devices(libdm_task_t, struct dm_ioctl *); 57 1.7 haad static int dm_dev_deps(libdm_task_t, struct dm_ioctl *); 58 1.7 haad static int dm_table_status(libdm_task_t, struct dm_ioctl *); 59 1.1 haad 60 1.1 haad int 61 1.1 haad nbsd_get_dm_major(uint32_t *major, int type) 62 1.1 haad { 63 1.1 haad size_t val_len,i; 64 1.1 haad struct kinfo_drivers *kd; 65 1.1 haad 66 1.1 haad if (sysctlbyname("kern.drivers",NULL,&val_len,NULL,0) < 0) { 67 1.1 haad printf("sysctlbyname failed"); 68 1.1 haad return 0; 69 1.1 haad } 70 1.1 haad 71 1.1 haad if ((kd = malloc (val_len)) == NULL){ 72 1.1 haad printf("malloc kd info error\n"); 73 1.1 haad return 0; 74 1.1 haad } 75 1.1 haad 76 1.1 haad if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 77 1.1 haad printf("sysctlbyname failed kd"); 78 1.1 haad return 0; 79 1.1 haad } 80 1.1 haad 81 1.1 haad for (i = 0, val_len /= sizeof(*kd); i < val_len; i++) { 82 1.7 haad if (strncmp(kd[i].d_name,DM_NAME,strlen(kd[i].d_name)) == 0) { 83 1.1 haad 84 1.1 haad if (type == DM_CHAR_MAJOR) 85 1.1 haad /* Set major to dm-driver char major number. */ 86 1.1 haad *major = kd[i].d_cmajor; 87 1.1 haad else 88 1.1 haad if (type == DM_BLOCK_MAJOR) 89 1.1 haad *major = kd[i].d_bmajor; 90 1.1 haad free(kd); 91 1.1 haad 92 1.1 haad return 1; 93 1.1 haad } 94 1.1 haad } 95 1.1 haad 96 1.1 haad free(kd); 97 1.1 haad 98 1.1 haad return 0; 99 1.1 haad } 100 1.1 haad 101 1.1 haad struct dm_ioctl* 102 1.7 haad nbsd_dm_dict_to_dmi(libdm_task_t task, const int cmd) 103 1.1 haad { 104 1.1 haad struct dm_ioctl *dmi; 105 1.7 haad 106 1.1 haad int r; 107 1.1 haad char *name, *uuid; 108 1.1 haad uint32_t major,minor; 109 1.7 haad 110 1.1 haad name = NULL; 111 1.1 haad uuid = NULL; 112 1.1 haad minor = 0; 113 1.7 haad 114 1.1 haad nbsd_get_dm_major(&major, DM_BLOCK_MAJOR); 115 1.7 haad 116 1.1 haad if (!(dmi = dm_malloc(DMI_SIZE))) 117 1.1 haad return NULL; 118 1.1 haad 119 1.7 haad memset(dmi, 0, DMI_SIZE); 120 1.7 haad 121 1.7 haad dmi->open_count = libdm_task_get_open_num(task); 122 1.7 haad dmi->event_nr = libdm_task_get_event_num(task); 123 1.7 haad dmi->flags = libdm_task_get_flags(task); 124 1.7 haad dmi->target_count = libdm_task_get_target_num(task); 125 1.7 haad 126 1.7 haad minor = libdm_task_get_minor(task); 127 1.1 haad 128 1.7 haad if (minor != 0) 129 1.1 haad dmi->dev = MKDEV(major, minor); 130 1.1 haad else 131 1.1 haad dmi->dev = 0; 132 1.7 haad 133 1.7 haad name = libdm_task_get_name(task); 134 1.7 haad uuid = libdm_task_get_uuid(task); 135 1.7 haad 136 1.1 haad /* Copy name and uuid to dm_ioctl. */ 137 1.7 haad if (name != NULL) 138 1.1 haad strlcpy(dmi->name, name, DM_NAME_LEN); 139 1.7 haad else 140 1.1 haad dmi->name[0] = '\0'; 141 1.7 haad 142 1.7 haad if (uuid != NULL) 143 1.1 haad strlcpy(dmi->uuid, uuid, DM_UUID_LEN); 144 1.7 haad else 145 1.1 haad dmi->uuid[0] = '\0'; 146 1.1 haad 147 1.1 haad /* dmi parsing values, size of dmi block and offset to data. */ 148 1.1 haad dmi->data_size = DMI_SIZE; 149 1.1 haad dmi->data_start = sizeof(struct dm_ioctl); 150 1.7 haad 151 1.7 haad libdm_task_get_cmd_version(task, dmi->version, 3); 152 1.1 haad 153 1.1 haad switch (cmd){ 154 1.1 haad 155 1.1 haad case DM_LIST_VERSIONS: 156 1.7 haad r = dm_list_versions(task, dmi); 157 1.1 haad if (r >= 0) 158 1.1 haad dmi->target_count = r; 159 1.1 haad break; 160 1.1 haad 161 1.1 haad case DM_LIST_DEVICES: 162 1.7 haad r = dm_list_devices(task, dmi); 163 1.1 haad if (r >= 0) 164 1.1 haad dmi->target_count = r; 165 1.7 haad break; 166 1.1 haad 167 1.1 haad case DM_TABLE_STATUS: 168 1.7 haad r = dm_table_status(task, dmi); 169 1.1 haad if (r >= 0) 170 1.1 haad dmi->target_count = r; 171 1.7 haad break; 172 1.1 haad 173 1.1 haad case DM_TABLE_DEPS: 174 1.7 haad r = dm_dev_deps(task, dmi); 175 1.1 haad if (r >= 0) 176 1.1 haad dmi->target_count = r; 177 1.7 haad break; 178 1.7 haad } 179 1.7 haad 180 1.1 haad return dmi; 181 1.1 haad } 182 1.1 haad 183 1.1 haad /* 184 1.1 haad * Parse dm_dict when targets command was called and fill dm_ioctl buffer with it. 185 1.1 haad * 186 1.1 haad * Return number of targets or if failed <0 error. 187 1.1 haad */ 188 1.1 haad 189 1.1 haad static int 190 1.7 haad dm_list_versions(libdm_task_t task, struct dm_ioctl *dmi) 191 1.1 haad { 192 1.1 haad struct dm_target_versions *dmtv,*odmtv; 193 1.1 haad 194 1.7 haad libdm_cmd_t cmd; 195 1.7 haad libdm_iter_t iter; 196 1.7 haad libdm_target_t target; 197 1.7 haad uint32_t ver[3]; 198 1.7 haad 199 1.1 haad char *name; 200 1.1 haad size_t j,i,slen,rec_size; 201 1.7 haad 202 1.1 haad odmtv = NULL; 203 1.1 haad name = NULL; 204 1.1 haad j = 0; 205 1.7 haad 206 1.1 haad dmtv = (struct dm_target_versions *)((uint8_t *)dmi + dmi->data_start); 207 1.1 haad 208 1.1 haad /* printf("dmi: vers: %d.%d.%d data_size: %d data_start: %d name: %s t_count: %d\n", 209 1.1 haad dmi->version[0],dmi->version[1],dmi->version[2],dmi->data_size,dmi->data_start, 210 1.1 haad dmi->name,dmi->target_count); 211 1.1 haad 212 1.1 haad printf("dmi: size: %d -- %p --- %p \n",sizeof(struct dm_ioctl),dmi,dmi+dmi->data_start); 213 1.1 haad printf("dmtv: size: %p --- %p\n",dmtv,(struct dm_target_versions *)(dmi+312));*/ 214 1.1 haad 215 1.1 haad /* get prop_array of target_version dictionaries */ 216 1.7 haad if ((cmd = libdm_task_get_cmd(task)) == NULL) 217 1.7 haad return -ENOENT; 218 1.7 haad 219 1.7 haad iter = libdm_cmd_iter_create(cmd); 220 1.7 haad 221 1.7 haad while((target = libdm_cmd_get_target(iter)) != NULL){ 222 1.7 haad j++; 223 1.1 haad 224 1.7 haad name = libdm_target_get_name(target); 225 1.7 haad 226 1.7 haad slen = strlen(name) + 1; 227 1.7 haad rec_size = sizeof(struct dm_target_versions) + slen + 1; 228 1.7 haad 229 1.7 haad if (rec_size > dmi->data_size) 230 1.7 haad return -ENOMEM; 231 1.7 haad 232 1.7 haad libdm_target_get_version(target, dmtv->version, sizeof(ver)); 233 1.7 haad 234 1.7 haad dmtv->next = rec_size; 235 1.7 haad strlcpy(dmtv->name,name,slen); 236 1.7 haad odmtv = dmtv; 237 1.7 haad dmtv =(struct dm_target_versions *)((uint8_t *)dmtv + rec_size); 238 1.7 haad 239 1.7 haad libdm_target_destroy(target); 240 1.7 haad } 241 1.7 haad 242 1.7 haad if (odmtv != NULL) 243 1.7 haad odmtv->next = 0; 244 1.1 haad 245 1.7 haad libdm_iter_destroy(iter); 246 1.1 haad 247 1.1 haad return j; 248 1.1 haad } 249 1.1 haad 250 1.1 haad /* 251 1.7 haad * List all available dm devices in system. 252 1.7 haad */ 253 1.1 haad static int 254 1.7 haad dm_list_devices(libdm_task_t task, struct dm_ioctl *dmi) 255 1.1 haad { 256 1.1 haad struct dm_name_list *dml,*odml; 257 1.7 haad 258 1.7 haad libdm_cmd_t cmd; 259 1.7 haad libdm_iter_t iter; 260 1.7 haad libdm_dev_t dev; 261 1.1 haad 262 1.1 haad uint32_t minor; 263 1.1 haad uint32_t major; 264 1.7 haad 265 1.1 haad char *name; 266 1.1 haad size_t j,slen,rec_size; 267 1.1 haad 268 1.1 haad odml = NULL; 269 1.1 haad name = NULL; 270 1.1 haad minor = 0; 271 1.1 haad j = 0; 272 1.1 haad 273 1.7 haad nbsd_get_dm_major(&major, DM_BLOCK_MAJOR); 274 1.7 haad 275 1.1 haad dml = (struct dm_name_list *)((uint8_t *)dmi + dmi->data_start); 276 1.1 haad 277 1.7 haad if ((cmd = libdm_task_get_cmd(task)) == NULL) 278 1.7 haad return -ENOENT; 279 1.7 haad 280 1.7 haad iter = libdm_cmd_iter_create(cmd); 281 1.7 haad 282 1.7 haad while((dev = libdm_cmd_get_dev(iter)) != NULL){ 283 1.1 haad 284 1.7 haad name = libdm_dev_get_name(dev); 285 1.7 haad minor = libdm_dev_get_minor(dev); 286 1.7 haad dml->dev = MKDEV(major, minor); 287 1.1 haad 288 1.7 haad slen = strlen(name) + 1; 289 1.7 haad rec_size = sizeof(struct dm_name_list) + slen + 1; 290 1.7 haad 291 1.7 haad if (rec_size > dmi->data_size) 292 1.7 haad return -ENOMEM; 293 1.7 haad 294 1.7 haad dml->next = rec_size; 295 1.7 haad strlcpy(dml->name, name, slen); 296 1.7 haad odml = dml; 297 1.7 haad dml =(struct dm_name_list *)((uint8_t *)dml + rec_size); 298 1.7 haad j++; 299 1.1 haad 300 1.7 haad libdm_dev_destroy(dev); 301 1.1 haad } 302 1.7 haad 303 1.7 haad if (odml != NULL) 304 1.7 haad odml->next = 0; 305 1.7 haad 306 1.7 haad libdm_iter_destroy(iter); 307 1.7 haad 308 1.1 haad return j; 309 1.1 haad } 310 1.1 haad 311 1.1 haad /* 312 1.7 haad * Print status of each table, target arguments, start sector, 313 1.1 haad * size and target name. 314 1.1 haad */ 315 1.1 haad static int 316 1.7 haad dm_table_status(libdm_task_t task, struct dm_ioctl *dmi) 317 1.1 haad { 318 1.1 haad struct dm_target_spec *dmts, *odmts; 319 1.1 haad 320 1.7 haad libdm_cmd_t cmd; 321 1.7 haad libdm_table_t table; 322 1.7 haad libdm_iter_t iter; 323 1.7 haad uint32_t flags; 324 1.1 haad 325 1.7 haad char *type, *params, *params_start; 326 1.7 haad size_t j, plen, rec_size, next; 327 1.1 haad 328 1.7 haad j = next = rec_size = 0; 329 1.1 haad params = NULL; 330 1.1 haad odmts = NULL; 331 1.1 haad plen = -1; 332 1.1 haad 333 1.7 haad dmts = (struct dm_target_spec *)((uint8_t *)dmi + dmi->data_start); 334 1.7 haad 335 1.7 haad if ((cmd = libdm_task_get_cmd(task)) == NULL) 336 1.7 haad return ENOENT; 337 1.7 haad 338 1.7 haad iter = libdm_cmd_iter_create(cmd); 339 1.7 haad 340 1.7 haad while ((table = libdm_cmd_get_table(iter)) != NULL) { 341 1.7 haad dmts->sector_start = libdm_table_get_start(table); 342 1.7 haad dmts->length = libdm_table_get_length(table); 343 1.7 haad dmts->status = libdm_table_get_status(table); 344 1.7 haad 345 1.7 haad type = libdm_table_get_target(table); 346 1.7 haad params = libdm_table_get_params(table); 347 1.7 haad 348 1.8 mlelstv if (params == NULL) 349 1.8 mlelstv params = ""; 350 1.7 haad 351 1.8 mlelstv plen = strlen(params) + 1; 352 1.7 haad rec_size = sizeof(struct dm_target_spec) + plen; 353 1.7 haad 354 1.7 haad /* 355 1.7 haad * In linux when copying table status from kernel next is 356 1.7 haad * number of bytes from the start of the first dm_target_spec 357 1.7 haad * structure. I don't know why but, it has to be done this way. 358 1.7 haad */ 359 1.7 haad next += rec_size; 360 1.1 haad 361 1.8 mlelstv if (rec_size > dmi->data_size) { 362 1.8 mlelstv libdm_table_destroy(table); 363 1.8 mlelstv libdm_iter_destroy(iter); 364 1.7 haad return -ENOMEM; 365 1.8 mlelstv } 366 1.7 haad 367 1.7 haad dmts->next = next; 368 1.7 haad strlcpy(dmts->target_type, type, DM_MAX_TYPE_NAME); 369 1.7 haad params_start = (char *)dmts + sizeof(struct dm_target_spec); 370 1.7 haad 371 1.8 mlelstv strlcpy(params_start, params, plen); 372 1.7 haad 373 1.7 haad odmts = dmts; 374 1.7 haad dmts = (struct dm_target_spec *)((uint8_t *)dmts + rec_size); 375 1.7 haad j++; 376 1.1 haad 377 1.7 haad libdm_table_destroy(table); 378 1.7 haad } 379 1.1 haad 380 1.7 haad if (odmts != NULL) 381 1.7 haad odmts->next = 0; 382 1.1 haad 383 1.7 haad libdm_iter_destroy(iter); 384 1.1 haad 385 1.1 haad return j; 386 1.1 haad } 387 1.1 haad 388 1.1 haad /* 389 1.7 haad * Print dm device dependiences, get minor/major number for 390 1.7 haad * devices. From kernel I will receive major:minor number of 391 1.7 haad * block device used with target. I have to translate it to 392 1.7 haad * raw device numbers and use them, because all other parts of lvm2 393 1.7 haad * uses raw devices internally. 394 1.1 haad */ 395 1.1 haad static int 396 1.7 haad dm_dev_deps(libdm_task_t task, struct dm_ioctl *dmi) 397 1.1 haad { 398 1.1 haad struct dm_target_deps *dmtd; 399 1.1 haad struct kinfo_drivers *kd; 400 1.7 haad 401 1.7 haad libdm_cmd_t cmd; 402 1.7 haad libdm_iter_t iter; 403 1.7 haad dev_t dev_deps; 404 1.7 haad 405 1.1 haad uint32_t major; 406 1.1 haad size_t val_len, i, j; 407 1.1 haad 408 1.7 haad dev_deps = 0; 409 1.1 haad j = 0; 410 1.1 haad i = 0; 411 1.7 haad 412 1.1 haad if (sysctlbyname("kern.drivers",NULL,&val_len,NULL,0) < 0) { 413 1.1 haad printf("sysctlbyname failed"); 414 1.1 haad return 0; 415 1.1 haad } 416 1.1 haad 417 1.7 haad if ((kd = malloc(val_len)) == NULL){ 418 1.1 haad printf("malloc kd info error\n"); 419 1.1 haad return 0; 420 1.1 haad } 421 1.1 haad 422 1.1 haad if (sysctlbyname("kern.drivers", kd, &val_len, NULL, 0) < 0) { 423 1.1 haad printf("sysctlbyname failed kd"); 424 1.1 haad return 0; 425 1.1 haad } 426 1.7 haad 427 1.1 haad dmtd = (struct dm_target_deps *)((uint8_t *)dmi + dmi->data_start); 428 1.1 haad 429 1.7 haad if ((cmd = libdm_task_get_cmd(task)) == NULL) 430 1.7 haad return -ENOENT; 431 1.7 haad 432 1.7 haad iter = libdm_cmd_iter_create(cmd); 433 1.1 haad 434 1.7 haad while((dev_deps = libdm_cmd_get_deps(iter)) != 0) { 435 1.7 haad for (i = 0, val_len /= sizeof(*kd); i < val_len; i++){ 436 1.7 haad if (kd[i].d_bmajor == MAJOR(dev_deps)) { 437 1.7 haad major = kd[i].d_cmajor; 438 1.7 haad break; 439 1.1 haad } 440 1.1 haad } 441 1.7 haad 442 1.7 haad dmtd->dev[j] = MKDEV(major, MINOR(dev_deps)); 443 1.7 haad 444 1.7 haad j++; 445 1.7 haad } 446 1.7 haad 447 1.1 haad dmtd->count = j; 448 1.1 haad 449 1.7 haad libdm_iter_destroy(iter); 450 1.7 haad free(kd); 451 1.7 haad 452 1.1 haad return j; 453 1.1 haad } 454