| 1 | /*      $NetBSD: libdm-nbsd-iface.c,v 1.12 2018/11/24 11:27:37 mlelstv Exp $        */ | 
| 2 |  | 
| 3 | /* | 
| 4 |  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. | 
| 5 |  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. | 
| 6 |  * Copyright (C) 2008 Adam Hamsik. All rights reserved. | 
| 7 |  * | 
| 8 |  * This file is part of the device-mapper userspace tools. | 
| 9 |  * | 
| 10 |  * This copyrighted material is made available to anyone wishing to use, | 
| 11 |  * modify, copy, or redistribute it subject to the terms and conditions | 
| 12 |  * of the GNU Lesser General Public License v.2.1. | 
| 13 |  * | 
| 14 |  * You should have received a copy of the GNU Lesser General Public License | 
| 15 |  * along with this program; if not, write to the Free Software Foundation, | 
| 16 |  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
| 17 |  */ | 
| 18 |  | 
| 19 | #include "dmlib.h" | 
| 20 | #include "libdm-targets.h" | 
| 21 | #include "libdm-common.h" | 
| 22 | #include "libdm-netbsd.h" | 
| 23 |  | 
| 24 | #include <sys/ioctl.h> | 
| 25 | #include <sys/sysctl.h> | 
| 26 |  | 
| 27 | #include <fcntl.h> | 
| 28 | #include <paths.h> | 
| 29 | #include <dirent.h> | 
| 30 | #include <fts.h> | 
| 31 | #include <limits.h> | 
| 32 |  | 
| 33 | #include <dm.h> | 
| 34 | #include <dev/dm/netbsd-dm.h> | 
| 35 |  | 
| 36 | #include <dm-ioctl.h> | 
| 37 |  | 
| 38 | #ifdef RUMP_ACTION | 
| 39 | #include <rump/rump.h> | 
| 40 | #include <rump/rump_syscalls.h> | 
| 41 | #endif | 
| 42 |  | 
| 43 | /* | 
| 44 |  * Ensure build compatibility. | 
| 45 |  * The hard-coded versions here are the highest present | 
| 46 |  * in the _cmd_data arrays. | 
| 47 |  */ | 
| 48 |  | 
| 49 | #if !((DM_VERSION_MAJOR == 1 && DM_VERSION_MINOR >= 0) || \ | 
| 50 |       (DM_VERSION_MAJOR == 4 && DM_VERSION_MINOR >= 0)) | 
| 51 | #error The version of dm-ioctl.h included is incompatible. | 
| 52 | #endif | 
| 53 |  | 
| 54 | /* dm major version no for running kernel */ | 
| 55 | static unsigned _dm_version_minor = 0; | 
| 56 | static unsigned _dm_version_patchlevel = 0; | 
| 57 |  | 
| 58 | static int _control_fd = -1; | 
| 59 | static int _version_checked = 0; | 
| 60 | static int _version_ok = 1; | 
| 61 | static unsigned _ioctl_buffer_double_factor = 0; | 
| 62 |  | 
| 63 | /* *INDENT-OFF* */ | 
| 64 |  | 
| 65 | /* | 
| 66 |  * XXX Remove this structure and write another own one | 
| 67 |  * I don't understand why ioctl calls has different | 
| 68 |  * names then dm task type | 
| 69 |  */ | 
| 70 | static struct cmd_data _cmd_data_v4[] = { | 
| 71 | 	{"create" ,	DM_DEV_CREATE,		{4, 0, 0}}, | 
| 72 | 	{"reload" ,	DM_TABLE_LOAD,		{4, 0, 0}}, /* DM_DEVICE_RELOAD */ | 
| 73 | 	{"remove" ,	DM_DEV_REMOVE,		{4, 0, 0}}, | 
| 74 | 	{"remove_all" ,	DM_REMOVE_ALL,		{4, 0, 0}}, | 
| 75 | 	{"suspend" ,	DM_DEV_SUSPEND,		{4, 0, 0}}, | 
| 76 | 	{"resume" ,	DM_DEV_SUSPEND,		{4, 0, 0}}, | 
| 77 | 	{"info" ,	DM_DEV_STATUS,		{4, 0, 0}}, | 
| 78 | 	{"deps" ,	DM_TABLE_DEPS,		{4, 0, 0}}, /* DM_DEVICE_DEPS */ | 
| 79 | 	{"rename" ,	DM_DEV_RENAME,		{4, 0, 0}}, | 
| 80 | 	{"version" ,	DM_VERSION,		{4, 0, 0}}, | 
| 81 | 	{"status" ,	DM_TABLE_STATUS,	{4, 0, 0}}, | 
| 82 | 	{"table" ,	DM_TABLE_STATUS,	{4, 0, 0}}, /* DM_DEVICE_TABLE */ | 
| 83 | 	{"waitevent" ,	DM_DEV_WAIT,		{4, 0, 0}}, | 
| 84 | 	{"names" ,	DM_LIST_DEVICES,	{4, 0, 0}}, | 
| 85 | 	{"clear" ,	DM_TABLE_CLEAR,		{4, 0, 0}}, | 
| 86 | 	{"mknodes" ,	DM_DEV_STATUS,		{4, 0, 0}}, | 
| 87 | #ifdef DM_LIST_VERSIONS | 
| 88 | 	{"targets" ,	DM_LIST_VERSIONS,	{4, 1, 0}}, | 
| 89 | #endif | 
| 90 | #ifdef DM_TARGET_MSG | 
| 91 | 	{"message" ,	DM_TARGET_MSG,		{4, 2, 0}}, | 
| 92 | #endif | 
| 93 | #ifdef DM_DEV_SET_GEOMETRY | 
| 94 | 	{"setgeometry" ,	DM_DEV_SET_GEOMETRY,	{4, 6, 0}}, | 
| 95 | #endif | 
| 96 | }; | 
| 97 | /* *INDENT-ON* */ | 
| 98 |  | 
| 99 | /* | 
| 100 |  * In NetBSD we use sysctl to get kernel drivers info. control device | 
| 101 |  * has predefined minor number 0 and major number = char major number | 
| 102 |  * of dm driver. First slot is therefore ocupied with control device | 
| 103 |  * and minor device starts from 1; | 
| 104 |  */ | 
| 105 |  | 
| 106 | static int _control_device_number(uint32_t *major, uint32_t *minor) | 
| 107 | { | 
| 108 |  | 
| 109 | 	nbsd_get_dm_major(major, DM_CHAR_MAJOR); | 
| 110 |  | 
| 111 | 	*minor = 0; | 
| 112 |  | 
| 113 | 	return 1; | 
| 114 | } | 
| 115 |  | 
| 116 | /* | 
| 117 |  * Returns 1 if exists; 0 if it doesn't; -1 if it's wrong | 
| 118 |  */ | 
| 119 | static int _control_exists(const char *control, uint32_t major, uint32_t minor) | 
| 120 | { | 
| 121 | 	struct stat buf; | 
| 122 |  | 
| 123 | 	if (stat(control, &buf) < 0) { | 
| 124 | 		if (errno != ENOENT) | 
| 125 | 			log_sys_error("stat" , control); | 
| 126 | 		return 0; | 
| 127 | 	} | 
| 128 |  | 
| 129 | 	if (!S_ISCHR(buf.st_mode)) { | 
| 130 | 		log_verbose("%s: Wrong inode type" , control); | 
| 131 | 		if (!unlink(control)) | 
| 132 | 			return 0; | 
| 133 | 		log_sys_error("unlink" , control); | 
| 134 | 		return -1; | 
| 135 | 	} | 
| 136 |  | 
| 137 | 	if (major && buf.st_rdev != MKDEV(major, minor)) { | 
| 138 | 		log_verbose("%s: Wrong device number: (%u, %u) instead of "  | 
| 139 | 			    "(%u, %u)" , control, | 
| 140 | 			    MAJOR(buf.st_mode), MINOR(buf.st_mode), | 
| 141 | 			    major, minor); | 
| 142 | 		if (!unlink(control)) | 
| 143 | 			return 0; | 
| 144 | 		log_sys_error("unlink" , control); | 
| 145 | 		return -1; | 
| 146 | 	} | 
| 147 |  | 
| 148 | 	return 1; | 
| 149 | } | 
| 150 |  | 
| 151 | static int _create_control(const char *control, uint32_t major, uint32_t minor) | 
| 152 | { | 
| 153 | 	int ret; | 
| 154 | 	mode_t old_umask; | 
| 155 |  | 
| 156 | 	if (!major) | 
| 157 | 		return 0; | 
| 158 |  | 
| 159 | 	old_umask = umask(DM_DEV_DIR_UMASK); | 
| 160 | 	ret = dm_create_dir(dm_dir()); | 
| 161 | 	umask(old_umask); | 
| 162 |  | 
| 163 | 	if (!ret) | 
| 164 | 		return 0; | 
| 165 |  | 
| 166 | 	log_verbose("Creating device %s (%u, %u)" , control, major, minor); | 
| 167 |  | 
| 168 | 	old_umask = umask(0); | 
| 169 | 	if (mknod(control, S_IFCHR | DM_CONTROL_DEVICE_MODE, | 
| 170 | 		  MKDEV(major, minor)) < 0)  { | 
| 171 | 		umask(old_umask); | 
| 172 | 		log_sys_error("mknod" , control); | 
| 173 | 		return 0; | 
| 174 | 	} | 
| 175 | 	umask(old_umask); | 
| 176 | 	if (chown(control, DM_DEVICE_UID, DM_DEVICE_GID) == -1) { | 
| 177 | 		log_sys_error("chown" , control); | 
| 178 | 		return 0; | 
| 179 | 	} | 
| 180 |  | 
| 181 |  | 
| 182 | 	return 1; | 
| 183 | } | 
| 184 |  | 
| 185 | /* Check if major is device-mapper block device major number */ | 
| 186 | int dm_is_dm_major(uint32_t major) | 
| 187 | { | 
| 188 | 	uint32_t dm_major; | 
| 189 |  | 
| 190 | 	nbsd_get_dm_major(&dm_major, DM_BLOCK_MAJOR); | 
| 191 |  | 
| 192 | 	if (major == dm_major) | 
| 193 | 		return 1; | 
| 194 |  | 
| 195 | 	return 0; | 
| 196 | } | 
| 197 |  | 
| 198 | /* Open control device if doesn't exist create it. */ | 
| 199 | static int _open_control(void) | 
| 200 | { | 
| 201 | 	char control[PATH_MAX]; | 
| 202 | 	uint32_t major = 0, minor = 0; | 
| 203 |  | 
| 204 | 	if (_control_fd != -1) | 
| 205 | 		return 1; | 
| 206 |  | 
| 207 | #ifdef RUMP_ACTION | 
| 208 | 	rump_init(); | 
| 209 | #endif | 
| 210 | 	snprintf(control, sizeof(control), "%s/control" , dm_dir()); | 
| 211 |  | 
| 212 | 	if (!_control_device_number(&major, &minor)) | 
| 213 | 		log_error("Is device-mapper driver missing from kernel?" ); | 
| 214 |  | 
| 215 | 	if (!_control_exists(control, major, minor) && | 
| 216 | 	    !_create_control(control, major, minor)) | 
| 217 | 		goto error; | 
| 218 |  | 
| 219 | 	if ((_control_fd = open(control, O_RDWR)) < 0) { | 
| 220 | 		log_sys_error("open" , control); | 
| 221 | 		goto error; | 
| 222 | 	} | 
| 223 |  | 
| 224 | 	return 1; | 
| 225 |  | 
| 226 | error: | 
| 227 | 	log_error("Failure to communicate with kernel device-mapper driver." ); | 
| 228 | 	return 0; | 
| 229 | } | 
| 230 |  | 
| 231 | /* | 
| 232 |  * Destroy dm task structure there are some dynamically alocated values there. | 
| 233 |  * name, uuid, head, tail list. | 
| 234 |  */ | 
| 235 | void dm_task_destroy(struct dm_task *dmt) | 
| 236 | { | 
| 237 | 	struct target *t, *n; | 
| 238 |  | 
| 239 | 	for (t = dmt->head; t; t = n) { | 
| 240 | 		n = t->next; | 
| 241 | 		dm_free(t->params); | 
| 242 | 		dm_free(t->type); | 
| 243 | 		dm_free(t); | 
| 244 | 	} | 
| 245 |  | 
| 246 | 	if (dmt->dev_name) | 
| 247 | 		dm_free(dmt->dev_name); | 
| 248 |  | 
| 249 | 	if (dmt->newname) | 
| 250 | 		dm_free(dmt->newname); | 
| 251 |  | 
| 252 | 	if (dmt->message) | 
| 253 | 		dm_free(dmt->message); | 
| 254 |  | 
| 255 | 	if (dmt->dmi.v4) | 
| 256 | 		dm_free(dmt->dmi.v4); | 
| 257 |  | 
| 258 | 	if (dmt->uuid) | 
| 259 | 		dm_free(dmt->uuid); | 
| 260 |  | 
| 261 | 	dm_free(dmt); | 
| 262 |  | 
| 263 | } | 
| 264 |  | 
| 265 | /* Get kernel driver version from dm_ioctl structure. */ | 
| 266 | int dm_task_get_driver_version(struct dm_task *dmt, char *version, size_t size) | 
| 267 | { | 
| 268 | 	unsigned *v; | 
| 269 |  | 
| 270 | 	if (!dmt->dmi.v4) { | 
| 271 | 		version[0] = '\0'; | 
| 272 | 		return 0; | 
| 273 | 	} | 
| 274 |  | 
| 275 | 	v = dmt->dmi.v4->version; | 
| 276 | 	snprintf(version, size, "%u.%u.%u" , v[0], v[1], v[2]); | 
| 277 | 	_dm_version_minor = v[1]; | 
| 278 | 	_dm_version_patchlevel = v[2]; | 
| 279 |  | 
| 280 | 	return 1; | 
| 281 | } | 
| 282 |  | 
| 283 | /* Get kernel driver protocol version and comapre it with library version. */ | 
| 284 | static int _check_version(char *version, size_t size) | 
| 285 | { | 
| 286 | 	struct dm_task *task; | 
| 287 | 	int r; | 
| 288 |  | 
| 289 | 	if (!(task = dm_task_create(DM_DEVICE_VERSION))) { | 
| 290 | 		log_error("Failed to get device-mapper version" ); | 
| 291 | 		version[0] = '\0'; | 
| 292 | 		return 0; | 
| 293 | 	} | 
| 294 |  | 
| 295 | 	r = dm_task_run(task); | 
| 296 | 	dm_task_get_driver_version(task, version, size); | 
| 297 | 	dm_task_destroy(task); | 
| 298 |  | 
| 299 | 	return r; | 
| 300 | } | 
| 301 |  | 
| 302 | /* | 
| 303 |  * Find out device-mapper's major version number the first time | 
| 304 |  * this is called and whether or not we support it. | 
| 305 |  */ | 
| 306 | int dm_check_version(void) | 
| 307 | { | 
| 308 | 	char dmversion[64]; | 
| 309 |  | 
| 310 | 	if (_version_checked) | 
| 311 | 		return _version_ok; | 
| 312 |  | 
| 313 | 	_version_checked = 1; | 
| 314 |  | 
| 315 | 	if (_check_version(dmversion, sizeof(dmversion))) | 
| 316 | 		return 1; | 
| 317 |  | 
| 318 |  | 
| 319 | 	return 0; | 
| 320 | } | 
| 321 |  | 
| 322 | int dm_cookie_supported(void) | 
| 323 | { | 
| 324 | 	return (0); | 
| 325 | } | 
| 326 |  | 
| 327 | /* Get next target(table description) from list pointed by dmt->head. */ | 
| 328 | void *dm_get_next_target(struct dm_task *dmt, void *next, | 
| 329 | 			 uint64_t *start, uint64_t *length, | 
| 330 | 			 char **target_type, char **params) | 
| 331 | { | 
| 332 | 	struct target *t = (struct target *) next; | 
| 333 |  | 
| 334 | 	if (!t) | 
| 335 | 		t = dmt->head; | 
| 336 |  | 
| 337 | 	if (!t) | 
| 338 | 		return NULL; | 
| 339 |  | 
| 340 | 	*start = t->start; | 
| 341 | 	*length = t->length; | 
| 342 | 	*target_type = t->type; | 
| 343 | 	*params = t->params; | 
| 344 |  | 
| 345 | 	return t->next; | 
| 346 | } | 
| 347 |  | 
| 348 | /* Unmarshall the target info returned from a status call */ | 
| 349 | static int _unmarshal_status(struct dm_task *dmt, struct dm_ioctl *dmi) | 
| 350 | { | 
| 351 | 	char *outbuf = (char *) dmi + dmi->data_start; | 
| 352 | 	char *outptr = outbuf; | 
| 353 | 	uint32_t i; | 
| 354 | 	struct dm_target_spec *spec; | 
| 355 |  | 
| 356 | 	for (i = 0; i < dmi->target_count; i++) { | 
| 357 | 		spec = (struct dm_target_spec *) outptr; | 
| 358 | 		if (!dm_task_add_target(dmt, spec->sector_start, | 
| 359 | 					spec->length, | 
| 360 | 					spec->target_type, | 
| 361 | 					outptr + sizeof(*spec))) { | 
| 362 | 			return 0; | 
| 363 | 		} | 
| 364 |  | 
| 365 | 		outptr = outbuf + spec->next; | 
| 366 | 	} | 
| 367 |  | 
| 368 | 	return 1; | 
| 369 | } | 
| 370 |  | 
| 371 | static char * | 
| 372 | get_dev_name(dev_t dev) | 
| 373 | { | 
| 374 | 	static char * const dirs[2] = { _PATH_DEV, NULL }; | 
| 375 | 	static char d_buf[MAXPATHLEN]; | 
| 376 | 	FTS *ftsp; | 
| 377 | 	FTSENT *fe; | 
| 378 | 	char *name; | 
| 379 |  | 
| 380 | 	if ((ftsp = fts_open(dirs, FTS_NOCHDIR | FTS_PHYSICAL, NULL)) == NULL) | 
| 381 | 		return NULL; | 
| 382 |  | 
| 383 | 	name = NULL; | 
| 384 | 	while ((fe = fts_read(ftsp)) != NULL) { | 
| 385 | 		if (fe->fts_info != FTS_DEFAULT) | 
| 386 | 			continue; | 
| 387 | 		if (S_ISBLK(fe->fts_statp->st_mode)) { | 
| 388 | 			if (fe->fts_statp->st_rdev == dev) { | 
| 389 | 				strlcpy(d_buf, fe->fts_path, sizeof(d_buf)); | 
| 390 | 				name = d_buf; | 
| 391 | 				break; | 
| 392 | 			} | 
| 393 | 		} | 
| 394 | 	} | 
| 395 |  | 
| 396 | 	fts_close(ftsp); | 
| 397 |  | 
| 398 | 	return name; | 
| 399 | } | 
| 400 |  | 
| 401 | /* | 
| 402 |  * @dev_major is major number of char device | 
| 403 |  * | 
| 404 |  * I have to find it's block device number and lookup dev in | 
| 405 |  * device database to find device path. | 
| 406 |  * | 
| 407 |  */ | 
| 408 |  | 
| 409 | int dm_format_dev(char *buf, int bufsize, uint32_t dev_major, | 
| 410 | 		  uint32_t dev_minor) | 
| 411 | { | 
| 412 | 	int r; | 
| 413 | 	uint32_t dm_major; | 
| 414 | 	int major; | 
| 415 | 	char *name; | 
| 416 | 	mode_t mode; | 
| 417 | 	dev_t dev; | 
| 418 | 	size_t val_len,i; | 
| 419 | 	struct kinfo_drivers *kd; | 
| 420 |  | 
| 421 | 	major = -1; | 
| 422 | 	mode = 0; | 
| 423 |  | 
| 424 | 	nbsd_get_dm_major(&dm_major, DM_BLOCK_MAJOR); | 
| 425 |  | 
| 426 | 	if (bufsize < 8) | 
| 427 | 		return 0; | 
| 428 |  | 
| 429 | 	if (sysctlbyname("kern.drivers" ,NULL,&val_len,NULL,0) < 0) { | 
| 430 | 		printf("sysctlbyname failed\n" ); | 
| 431 | 		return 0; | 
| 432 | 	} | 
| 433 |  | 
| 434 | 	if ((kd = malloc (val_len)) == NULL){ | 
| 435 | 		printf("malloc kd info error\n" ); | 
| 436 | 		return 0; | 
| 437 | 	} | 
| 438 |  | 
| 439 | 	if (sysctlbyname("kern.drivers" , kd, &val_len, NULL, 0) < 0) { | 
| 440 | 		free(kd); | 
| 441 | 		printf("sysctlbyname failed kd\n" ); | 
| 442 | 		return 0; | 
| 443 | 	} | 
| 444 |  | 
| 445 | 	for (i = 0, val_len /= sizeof(*kd); i < val_len; i++){ | 
| 446 | 		if (kd[i].d_cmajor == dev_major) { | 
| 447 | 			major = kd[i].d_bmajor; | 
| 448 | 			break; | 
| 449 | 		} | 
| 450 | 	} | 
| 451 |  | 
| 452 | 	if (major != -1) { | 
| 453 | 		dev = MKDEV(major,dev_minor); | 
| 454 | 		mode |= S_IFBLK; | 
| 455 | 		if ((name = devname(dev,mode)) == NULL) | 
| 456 | 			name = get_dev_name(dev); | 
| 457 | 	} else | 
| 458 | 		name = NULL; | 
| 459 |  | 
| 460 | 	free(kd); | 
| 461 |  | 
| 462 | 	if (name == NULL) | 
| 463 | 		r = snprintf(buf, (size_t) bufsize, "%d:%d" , dev_major, dev_minor); | 
| 464 | 	else | 
| 465 | 		r = snprintf(buf, (size_t) bufsize, _PATH_DEV "%s" , name); | 
| 466 |  | 
| 467 | 	if (r < 0 || r > bufsize - 1) | 
| 468 | 		return 0; | 
| 469 |  | 
| 470 | 	return 1; | 
| 471 | } | 
| 472 |  | 
| 473 | /* Fill info from dm_ioctl structure. Look at DM_EXISTS_FLAG*/ | 
| 474 | int dm_task_get_info(struct dm_task *dmt, struct dm_info *info) | 
| 475 | { | 
| 476 | 	if (!dmt->dmi.v4) | 
| 477 | 		return 0; | 
| 478 |  | 
| 479 | 	memset(info, 0, sizeof(*info)); | 
| 480 |  | 
| 481 | 	info->exists = dmt->dmi.v4->flags & DM_EXISTS_FLAG ? 1 : 0; | 
| 482 | 	if (!info->exists) | 
| 483 | 		return 1; | 
| 484 |  | 
| 485 | 	info->suspended = dmt->dmi.v4->flags & DM_SUSPEND_FLAG ? 1 : 0; | 
| 486 | 	info->read_only = dmt->dmi.v4->flags & DM_READONLY_FLAG ? 1 : 0; | 
| 487 | 	info->live_table = dmt->dmi.v4->flags & DM_ACTIVE_PRESENT_FLAG ? 1 : 0; | 
| 488 | 	info->inactive_table = dmt->dmi.v4->flags & DM_INACTIVE_PRESENT_FLAG ? | 
| 489 | 	    1 : 0; | 
| 490 | 	info->target_count = dmt->dmi.v4->target_count; | 
| 491 | 	info->open_count = dmt->dmi.v4->open_count; | 
| 492 | 	info->event_nr = dmt->dmi.v4->event_nr; | 
| 493 |  | 
| 494 | 	nbsd_get_dm_major(&info->major, DM_BLOCK_MAJOR); /* get netbsd dm device major number */ | 
| 495 | 	info->minor = MINOR(dmt->dmi.v4->dev); | 
| 496 |  | 
| 497 | 	return 1; | 
| 498 | } | 
| 499 |  | 
| 500 | /* Unsupported on NetBSD */ | 
| 501 | uint32_t dm_task_get_read_ahead(const struct dm_task *dmt, uint32_t *read_ahead) | 
| 502 | { | 
| 503 | 	*read_ahead = DM_READ_AHEAD_NONE; | 
| 504 | 	return 1; | 
| 505 | } | 
| 506 |  | 
| 507 | const char *dm_task_get_name(const struct dm_task *dmt) | 
| 508 | { | 
| 509 |  | 
| 510 | 	return (dmt->dmi.v4->name); | 
| 511 | } | 
| 512 |  | 
| 513 | const char *dm_task_get_uuid(const struct dm_task *dmt) | 
| 514 | { | 
| 515 |  | 
| 516 | 	return (dmt->dmi.v4->uuid); | 
| 517 | } | 
| 518 |  | 
| 519 | struct dm_deps *dm_task_get_deps(struct dm_task *dmt) | 
| 520 | { | 
| 521 | 	return (struct dm_deps *) (((void *) dmt->dmi.v4) + | 
| 522 | 				   dmt->dmi.v4->data_start); | 
| 523 | } | 
| 524 |  | 
| 525 | struct dm_names *dm_task_get_names(struct dm_task *dmt) | 
| 526 | { | 
| 527 | 	return (struct dm_names *) (((void *) dmt->dmi.v4) + | 
| 528 | 				    dmt->dmi.v4->data_start); | 
| 529 | } | 
| 530 |  | 
| 531 | struct dm_versions *dm_task_get_versions(struct dm_task *dmt) | 
| 532 | { | 
| 533 | 	return (struct dm_versions *) (((void *) dmt->dmi.v4) + | 
| 534 | 				       dmt->dmi.v4->data_start); | 
| 535 | } | 
| 536 |  | 
| 537 | int dm_task_set_ro(struct dm_task *dmt) | 
| 538 | { | 
| 539 | 	dmt->read_only = 1; | 
| 540 | 	return 1; | 
| 541 | } | 
| 542 |  | 
| 543 | /* Unsupported on NetBSD */ | 
| 544 | int dm_task_set_read_ahead(struct dm_task *dmt, uint32_t read_ahead, | 
| 545 | 			   uint32_t read_ahead_flags) | 
| 546 | { | 
| 547 | 	return 1; | 
| 548 | } | 
| 549 |  | 
| 550 | int dm_task_suppress_identical_reload(struct dm_task *dmt) | 
| 551 | { | 
| 552 | 	dmt->suppress_identical_reload = 1; | 
| 553 | 	return 1; | 
| 554 | } | 
| 555 |  | 
| 556 | int dm_task_set_newname(struct dm_task *dmt, const char *newname) | 
| 557 | { | 
| 558 | 	if (!(dmt->newname = dm_strdup(newname))) { | 
| 559 | 		log_error("dm_task_set_newname: strdup(%s) failed" , newname); | 
| 560 | 		return 0; | 
| 561 | 	} | 
| 562 |  | 
| 563 | 	return 1; | 
| 564 | } | 
| 565 |  | 
| 566 | int dm_task_set_message(struct dm_task *dmt, const char *message) | 
| 567 | { | 
| 568 | 	if (!(dmt->message = dm_strdup(message))) { | 
| 569 | 		log_error("dm_task_set_message: strdup(%s) failed" , message); | 
| 570 | 		return 0; | 
| 571 | 	} | 
| 572 |  | 
| 573 | 	return 1; | 
| 574 | } | 
| 575 |  | 
| 576 | int dm_task_set_sector(struct dm_task *dmt, uint64_t sector) | 
| 577 | { | 
| 578 | 	dmt->sector = sector; | 
| 579 |  | 
| 580 | 	return 1; | 
| 581 | } | 
| 582 |  | 
| 583 | /* Unsupported in NetBSD */ | 
| 584 | int dm_task_set_geometry(struct dm_task *dmt, const char *cylinders, | 
| 585 |     const char *heads, const char *sectors, const char *start) | 
| 586 | { | 
| 587 | 	return 0; | 
| 588 | } | 
| 589 |  | 
| 590 | int dm_task_no_flush(struct dm_task *dmt) | 
| 591 | { | 
| 592 | 	dmt->no_flush = 1; | 
| 593 |  | 
| 594 | 	return 1; | 
| 595 | } | 
| 596 |  | 
| 597 | int dm_task_no_open_count(struct dm_task *dmt) | 
| 598 | { | 
| 599 | 	dmt->no_open_count = 1; | 
| 600 |  | 
| 601 | 	return 1; | 
| 602 | } | 
| 603 |  | 
| 604 | int dm_task_skip_lockfs(struct dm_task *dmt) | 
| 605 | { | 
| 606 | 	dmt->skip_lockfs = 1; | 
| 607 |  | 
| 608 | 	return 1; | 
| 609 | } | 
| 610 |  | 
| 611 | int dm_task_query_inactive_table(struct dm_task *dmt) | 
| 612 | { | 
| 613 | 	dmt->query_inactive_table = 1; | 
| 614 |  | 
| 615 | 	return 1; | 
| 616 | } | 
| 617 |  | 
| 618 | int dm_task_set_event_nr(struct dm_task *dmt, uint32_t event_nr) | 
| 619 | { | 
| 620 | 	dmt->event_nr = event_nr; | 
| 621 |  | 
| 622 | 	return 1; | 
| 623 | } | 
| 624 |  | 
| 625 | /* Allocate one target(table description) entry. */ | 
| 626 | struct target *create_target(uint64_t start, uint64_t len, const char *type, | 
| 627 | 			     const char *params) | 
| 628 | { | 
| 629 | 	struct target *t = dm_malloc(sizeof(*t)); | 
| 630 |  | 
| 631 | 	if (!t) { | 
| 632 | 		log_error("create_target: malloc(%"  PRIsize_t ") failed" , | 
| 633 | 			  sizeof(*t)); | 
| 634 | 		return NULL; | 
| 635 | 	} | 
| 636 |  | 
| 637 | 	memset(t, 0, sizeof(*t)); | 
| 638 |  | 
| 639 | 	if (!(t->params = dm_strdup(params))) { | 
| 640 | 		log_error("create_target: strdup(params) failed" ); | 
| 641 | 		goto bad; | 
| 642 | 	} | 
| 643 |  | 
| 644 | 	if (!(t->type = dm_strdup(type))) { | 
| 645 | 		log_error("create_target: strdup(type) failed" ); | 
| 646 | 		goto bad; | 
| 647 | 	} | 
| 648 |  | 
| 649 | 	t->start = start; | 
| 650 | 	t->length = len; | 
| 651 | 	return t; | 
| 652 |  | 
| 653 |       bad: | 
| 654 | 	dm_free(t->params); | 
| 655 | 	dm_free(t->type); | 
| 656 | 	dm_free(t); | 
| 657 | 	return NULL; | 
| 658 | } | 
| 659 |  | 
| 660 | /* Parse given dm task structure to proplib dictionary.  */ | 
| 661 | static int _flatten(struct dm_task *dmt, libdm_task_t task) | 
| 662 | { | 
| 663 | 	libdm_cmd_t cmd; | 
| 664 | 	libdm_table_t table; | 
| 665 |  | 
| 666 | 	struct target *t; | 
| 667 |  | 
| 668 | 	size_t len; | 
| 669 | 	char type[DM_MAX_TYPE_NAME]; | 
| 670 |  | 
| 671 | 	uint32_t major, flags; | 
| 672 | 	int count = 0; | 
| 673 |  | 
| 674 | 	flags = 0; | 
| 675 |  | 
| 676 | 	cmd = libdm_cmd_create(); | 
| 677 |  | 
| 678 | 	for (t = dmt->head; t; t = t->next) { | 
| 679 | 		strlcpy(type,t->type,DM_MAX_TYPE_NAME); | 
| 680 |  | 
| 681 | 		table = libdm_table_create(); | 
| 682 |  | 
| 683 | 		libdm_table_set_start(t->start, table); | 
| 684 | 		libdm_table_set_length(t->length, table); | 
| 685 | 		libdm_table_set_target(type, table); | 
| 686 | 		libdm_table_set_params(t->params, table); | 
| 687 | 		libdm_cmd_set_table(table, cmd); | 
| 688 |  | 
| 689 | 		libdm_table_destroy(table); | 
| 690 |  | 
| 691 | 		count++; | 
| 692 | 	} | 
| 693 |  | 
| 694 | 	if (count && (dmt->sector || dmt->message)) { | 
| 695 | 		log_error("targets and message are incompatible" ); | 
| 696 | 		return -1; | 
| 697 | 	} | 
| 698 |  | 
| 699 | 	if (count && dmt->newname) { | 
| 700 | 		log_error("targets and newname are incompatible" ); | 
| 701 | 		return -1; | 
| 702 | 	} | 
| 703 |  | 
| 704 | 	if (count && dmt->geometry) { | 
| 705 | 		log_error("targets and geometry are incompatible" ); | 
| 706 | 		return -1; | 
| 707 | 	} | 
| 708 |  | 
| 709 | 	if (dmt->newname && (dmt->sector || dmt->message)) { | 
| 710 | 		log_error("message and newname are incompatible" ); | 
| 711 | 		return -1; | 
| 712 | 	} | 
| 713 |  | 
| 714 | 	if (dmt->newname && dmt->geometry) { | 
| 715 | 		log_error("geometry and newname are incompatible" ); | 
| 716 | 		return -1; | 
| 717 | 	} | 
| 718 |  | 
| 719 | 	if (dmt->geometry && (dmt->sector || dmt->message)) { | 
| 720 | 		log_error("geometry and message are incompatible" ); | 
| 721 | 		return -1; | 
| 722 | 	} | 
| 723 |  | 
| 724 | 	if (dmt->sector && !dmt->message) { | 
| 725 | 		log_error("message is required with sector" ); | 
| 726 | 		return -1; | 
| 727 | 	} | 
| 728 |  | 
| 729 | 	if (dmt->newname) | 
| 730 | 		len += strlen(dmt->newname) + 1; | 
| 731 |  | 
| 732 | 	if (dmt->message) | 
| 733 | 		len += sizeof(struct dm_target_msg) + strlen(dmt->message) + 1; | 
| 734 |  | 
| 735 | 	if (dmt->geometry) | 
| 736 | 		len += strlen(dmt->geometry) + 1; | 
| 737 |  | 
| 738 | 	nbsd_get_dm_major(&major, DM_BLOCK_MAJOR); | 
| 739 | 	/* | 
| 740 | 	 * Only devices with major which is equal to netbsd dm major | 
| 741 | 	 * dm devices in NetBSD can't have more majors then one assigned to dm. | 
| 742 | 	 */ | 
| 743 | 	if (dmt->major != major && dmt->major != -1) | 
| 744 | 		return -1; | 
| 745 |  | 
| 746 | 	if (dmt->minor >= 0) { | 
| 747 | 		flags |= DM_PERSISTENT_DEV_FLAG; | 
| 748 | 		libdm_task_set_minor(dmt->minor, task); | 
| 749 | 	} | 
| 750 |  | 
| 751 | 	/* Set values to dictionary. */ | 
| 752 | 	if (dmt->dev_name) | 
| 753 | 		libdm_task_set_name(dmt->dev_name, task); | 
| 754 |  | 
| 755 | 	if (dmt->uuid) | 
| 756 | 		libdm_task_set_uuid(dmt->uuid, task); | 
| 757 |  | 
| 758 | 	if (dmt->type == DM_DEVICE_SUSPEND) | 
| 759 | 		flags |= DM_SUSPEND_FLAG; | 
| 760 | 	if (dmt->no_flush) | 
| 761 | 		flags |= DM_NOFLUSH_FLAG; | 
| 762 | 	if (dmt->read_only) | 
| 763 | 		flags |= DM_READONLY_FLAG; | 
| 764 | 	if (dmt->skip_lockfs) | 
| 765 | 		flags |= DM_SKIP_LOCKFS_FLAG; | 
| 766 |  | 
| 767 | 	if (dmt->query_inactive_table) { | 
| 768 | 		if (_dm_version_minor < 16) | 
| 769 | 			log_warn("WARNING: Inactive table query unsupported "  | 
| 770 | 				 "by kernel.  It will use live table." ); | 
| 771 | 		flags |= DM_QUERY_INACTIVE_TABLE_FLAG; | 
| 772 | 	} | 
| 773 |  | 
| 774 | 	libdm_task_set_flags(task, flags); | 
| 775 |  | 
| 776 | //	prop_dictionary_set_uint32(dm_dict, DM_IOCTL_EVENT, dmt->event_nr); | 
| 777 |  | 
| 778 | 	if (dmt->newname) | 
| 779 | 		libdm_dev_set_newname(dmt->newname, cmd); | 
| 780 |  | 
| 781 | 	/* Add array for all COMMAND specific data. */ | 
| 782 | 	libdm_task_set_cmd(cmd, task); | 
| 783 | 	libdm_cmd_destroy(cmd); | 
| 784 |  | 
| 785 | 	return 0; | 
| 786 | } | 
| 787 |  | 
| 788 | static int _process_mapper_dir(struct dm_task *dmt) | 
| 789 | { | 
| 790 | 	struct dirent *dirent; | 
| 791 | 	DIR *d; | 
| 792 | 	const char *dir; | 
| 793 | 	int r = 1; | 
| 794 |  | 
| 795 | 	dir = dm_dir(); | 
| 796 | 	if (!(d = opendir(dir))) { | 
| 797 | 		log_sys_error("opendir" , dir); | 
| 798 | 		return 0; | 
| 799 | 	} | 
| 800 |  | 
| 801 | 	while ((dirent = readdir(d))) { | 
| 802 | 		if (!strcmp(dirent->d_name, "." ) || | 
| 803 | 		    !strcmp(dirent->d_name, ".." ) || | 
| 804 | 		    !strcmp(dirent->d_name, "control" )) | 
| 805 | 			continue; | 
| 806 | 		dm_task_set_name(dmt, dirent->d_name); | 
| 807 | 		dm_task_run(dmt); | 
| 808 | 	} | 
| 809 |  | 
| 810 | 	if (closedir(d)) | 
| 811 | 		log_sys_error("closedir" , dir); | 
| 812 |  | 
| 813 | 	return r; | 
| 814 | } | 
| 815 |  | 
| 816 | /* Get list of all devices. */ | 
| 817 | static int _process_all_v4(struct dm_task *dmt) | 
| 818 | { | 
| 819 | 	struct dm_task *task; | 
| 820 | 	struct dm_names *names; | 
| 821 | 	unsigned next = 0; | 
| 822 | 	int r = 1; | 
| 823 |  | 
| 824 | 	if (!(task = dm_task_create(DM_DEVICE_LIST))) | 
| 825 | 		return 0; | 
| 826 |  | 
| 827 | 	if (!dm_task_run(task)) { | 
| 828 | 		r = 0; | 
| 829 | 		goto out; | 
| 830 | 	} | 
| 831 |  | 
| 832 | 	if (!(names = dm_task_get_names(task))) { | 
| 833 | 		r = 0; | 
| 834 | 		goto out; | 
| 835 | 	} | 
| 836 |  | 
| 837 | 	if (!names->dev) | 
| 838 | 		goto out; | 
| 839 |  | 
| 840 | 	do { | 
| 841 | 		names = (void *) names + next; | 
| 842 | 		if (!dm_task_set_name(dmt, names->name)) { | 
| 843 | 			r = 0; | 
| 844 | 			goto out; | 
| 845 | 		} | 
| 846 | 		if (!dm_task_run(dmt)) | 
| 847 | 			r = 0; | 
| 848 | 		next = names->next; | 
| 849 | 	} while (next); | 
| 850 |  | 
| 851 |       out: | 
| 852 | 	dm_task_destroy(task); | 
| 853 | 	return r; | 
| 854 | } | 
| 855 |  | 
| 856 | static int _mknodes_v4(struct dm_task *dmt) | 
| 857 | { | 
| 858 | 	(void) _process_mapper_dir(dmt); | 
| 859 |  | 
| 860 | 	return _process_all_v4(dmt); | 
| 861 | } | 
| 862 |  | 
| 863 | /* Create new device and load table to it. */ | 
| 864 | static int _create_and_load_v4(struct dm_task *dmt) | 
| 865 | { | 
| 866 | 	struct dm_task *task; | 
| 867 | 	int r; | 
| 868 |  | 
| 869 | 	printf("create and load called \n" ); | 
| 870 |  | 
| 871 | 	/* Use new task struct to create the device */ | 
| 872 | 	if (!(task = dm_task_create(DM_DEVICE_CREATE))) { | 
| 873 | 		log_error("Failed to create device-mapper task struct" ); | 
| 874 | 		return 0; | 
| 875 | 	} | 
| 876 |  | 
| 877 | 	/* Copy across relevant fields */ | 
| 878 | 	if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) { | 
| 879 | 		dm_task_destroy(task); | 
| 880 | 		return 0; | 
| 881 | 	} | 
| 882 |  | 
| 883 | 	if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) { | 
| 884 | 		dm_task_destroy(task); | 
| 885 | 		return 0; | 
| 886 | 	} | 
| 887 |  | 
| 888 | 	task->major = dmt->major; | 
| 889 | 	task->minor = dmt->minor; | 
| 890 | 	task->uid = dmt->uid; | 
| 891 | 	task->gid = dmt->gid; | 
| 892 | 	task->mode = dmt->mode; | 
| 893 |  | 
| 894 | 	r = dm_task_run(task); | 
| 895 | 	dm_task_destroy(task); | 
| 896 | 	if (!r) | 
| 897 | 		return r; | 
| 898 |  | 
| 899 | 	/* Next load the table */ | 
| 900 | 	if (!(task = dm_task_create(DM_DEVICE_RELOAD))) { | 
| 901 | 		log_error("Failed to create device-mapper task struct" ); | 
| 902 | 		return 0; | 
| 903 | 	} | 
| 904 |  | 
| 905 | 	/* Copy across relevant fields */ | 
| 906 | 	if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) { | 
| 907 | 		dm_task_destroy(task); | 
| 908 | 		return 0; | 
| 909 | 	} | 
| 910 |  | 
| 911 | 	task->read_only = dmt->read_only; | 
| 912 | 	task->head = dmt->head; | 
| 913 | 	task->tail = dmt->tail; | 
| 914 |  | 
| 915 | 	r = dm_task_run(task); | 
| 916 |  | 
| 917 | 	task->head = NULL; | 
| 918 | 	task->tail = NULL; | 
| 919 | 	dm_task_destroy(task); | 
| 920 | 	if (!r) | 
| 921 | 		goto revert; | 
| 922 |  | 
| 923 | 	/* Use the original structure last so the info will be correct */ | 
| 924 | 	dmt->type = DM_DEVICE_RESUME; | 
| 925 | 	dm_free(dmt->uuid); | 
| 926 | 	dmt->uuid = NULL; | 
| 927 |  | 
| 928 | 	r = dm_task_run(dmt); | 
| 929 |  | 
| 930 | 	if (r) | 
| 931 | 		return r; | 
| 932 |  | 
| 933 |       revert: | 
| 934 |  	dmt->type = DM_DEVICE_REMOVE; | 
| 935 | 	dm_free(dmt->uuid); | 
| 936 | 	dmt->uuid = NULL; | 
| 937 |  | 
| 938 | 	if (!dm_task_run(dmt)) | 
| 939 | 		log_error("Failed to revert device creation." ); | 
| 940 |  | 
| 941 | 	return r; | 
| 942 | } | 
| 943 |  | 
| 944 | uint64_t dm_task_get_existing_table_size(struct dm_task *dmt) | 
| 945 | { | 
| 946 | 	return dmt->existing_table_size; | 
| 947 | } | 
| 948 |  | 
| 949 | static int _reload_with_suppression_v4(struct dm_task *dmt) | 
| 950 | { | 
| 951 | 	struct dm_task *task; | 
| 952 | 	struct target *t1, *t2; | 
| 953 | 	int r; | 
| 954 |  | 
| 955 | 	/* New task to get existing table information */ | 
| 956 | 	if (!(task = dm_task_create(DM_DEVICE_TABLE))) { | 
| 957 | 		log_error("Failed to create device-mapper task struct" ); | 
| 958 | 		return 0; | 
| 959 | 	} | 
| 960 |  | 
| 961 | 	/* Copy across relevant fields */ | 
| 962 | 	if (dmt->dev_name && !dm_task_set_name(task, dmt->dev_name)) { | 
| 963 | 		dm_task_destroy(task); | 
| 964 | 		return 0; | 
| 965 | 	} | 
| 966 |  | 
| 967 | 	if (dmt->uuid && !dm_task_set_uuid(task, dmt->uuid)) { | 
| 968 | 		dm_task_destroy(task); | 
| 969 | 		return 0; | 
| 970 | 	} | 
| 971 |  | 
| 972 | 	task->major = dmt->major; | 
| 973 | 	task->minor = dmt->minor; | 
| 974 |  | 
| 975 | 	r = dm_task_run(task); | 
| 976 |  | 
| 977 | 	if (!r) { | 
| 978 | 		dm_task_destroy(task); | 
| 979 | 		return r; | 
| 980 | 	} | 
| 981 |  | 
| 982 | 	/* Store existing table size */ | 
| 983 | 	t2 = task->head; | 
| 984 | 	while (t2 && t2->next) | 
| 985 | 		t2 = t2->next; | 
| 986 | 	dmt->existing_table_size = t2 ? t2->start + t2->length : 0; | 
| 987 |  | 
| 988 | 	if ((task->dmi.v4->flags & DM_READONLY_FLAG) ? 1 : 0 != dmt->read_only) | 
| 989 | 		goto no_match; | 
| 990 |  | 
| 991 | 	t1 = dmt->head; | 
| 992 | 	t2 = task->head; | 
| 993 |  | 
| 994 | 	while (t1 && t2) { | 
| 995 | 		while (t2->params[strlen(t2->params) - 1] == ' ') | 
| 996 | 			t2->params[strlen(t2->params) - 1] = '\0'; | 
| 997 | 		if ((t1->start != t2->start) || | 
| 998 | 		    (t1->length != t2->length) || | 
| 999 | 		    (strcmp(t1->type, t2->type)) || | 
| 1000 | 		    (strcmp(t1->params, t2->params))) | 
| 1001 | 			goto no_match; | 
| 1002 | 		t1 = t1->next; | 
| 1003 | 		t2 = t2->next; | 
| 1004 | 	} | 
| 1005 |  | 
| 1006 | 	if (!t1 && !t2) { | 
| 1007 | 		dmt->dmi.v4 = task->dmi.v4; | 
| 1008 | 		task->dmi.v4 = NULL; | 
| 1009 | 		dm_task_destroy(task); | 
| 1010 | 		return 1; | 
| 1011 | 	} | 
| 1012 |  | 
| 1013 | no_match: | 
| 1014 | 	dm_task_destroy(task); | 
| 1015 |  | 
| 1016 | 	/* Now do the original reload */ | 
| 1017 | 	dmt->suppress_identical_reload = 0; | 
| 1018 | 	r = dm_task_run(dmt); | 
| 1019 |  | 
| 1020 | 	return r; | 
| 1021 | } | 
| 1022 |  | 
| 1023 | /* | 
| 1024 |  * This function is heart of NetBSD libdevmapper-> device-mapper kernel protocol | 
| 1025 |  * It creates proplib_dictionary from dm task structure and sends it to NetBSD | 
| 1026 |  * kernel driver. After succesfull ioctl it create dmi structure from returned | 
| 1027 |  * proplib dictionary. This way I keep number of changes in NetBSD version of | 
| 1028 |  * libdevmapper as small as posible. | 
| 1029 |  */ | 
| 1030 | static struct dm_ioctl *_do_dm_ioctl(struct dm_task *dmt, unsigned command) | 
| 1031 | { | 
| 1032 | 	struct dm_ioctl *dmi; | 
| 1033 | 	libdm_task_t task; | 
| 1034 |  | 
| 1035 | 	task = libdm_task_create(_cmd_data_v4[dmt->type].name); | 
| 1036 |  | 
| 1037 | 	/* Parse dmi from libdevmapper to dictionary */ | 
| 1038 | 	if (_flatten(dmt, task) < 0) | 
| 1039 | 		goto bad; | 
| 1040 |  | 
| 1041 | 	if (dmt->type == DM_DEVICE_TABLE) | 
| 1042 | 		libdm_task_set_status_flag(task); | 
| 1043 |  | 
| 1044 | 	libdm_task_set_exists_flag(task); | 
| 1045 |  | 
| 1046 | 	log_very_verbose("Ioctl type  %s --- flags %d" ,_cmd_data_v4[dmt->type].name, libdm_task_get_flags(task)); | 
| 1047 | 	/* Send dictionary to kernel and wait for reply. */ | 
| 1048 | 	if (libdm_task_run(task) != 0) { | 
| 1049 | 		if (errno == ENOENT && | 
| 1050 | 		    ((dmt->type == DM_DEVICE_INFO) || | 
| 1051 | 			(dmt->type == DM_DEVICE_MKNODES) || | 
| 1052 | 			(dmt->type == DM_DEVICE_STATUS))) { | 
| 1053 |  | 
| 1054 | 			/* | 
| 1055 | 			 * Linux version doesn't fail when ENOENT is returned | 
| 1056 | 			 * for nonexisting device after info, deps, mknodes call. | 
| 1057 | 			 * It returns dmi sent to kernel with DM_EXISTS_FLAG = 0; | 
| 1058 | 			 */ | 
| 1059 |  | 
| 1060 | 			dmi = nbsd_dm_dict_to_dmi(task, _cmd_data_v4[dmt->type].cmd); | 
| 1061 |  | 
| 1062 | 			libdm_task_del_exists_flag(task); | 
| 1063 |  | 
| 1064 | 			libdm_task_destroy(task); | 
| 1065 |  | 
| 1066 | 			goto out; | 
| 1067 | 		} else { | 
| 1068 | 			log_error("ioctl %s call failed with errno %d\n" , | 
| 1069 | 					  _cmd_data_v4[dmt->type].name, errno); | 
| 1070 | 			libdm_task_destroy(task); | 
| 1071 | 			goto bad; | 
| 1072 | 		} | 
| 1073 | 	} | 
| 1074 |  | 
| 1075 | 	/* Parse kernel dictionary to dmi structure and return it to libdevmapper. */ | 
| 1076 | 	dmi = nbsd_dm_dict_to_dmi(task, _cmd_data_v4[dmt->type].cmd); | 
| 1077 |  | 
| 1078 | 	libdm_task_destroy(task); | 
| 1079 | out: | 
| 1080 | 	return dmi; | 
| 1081 | bad: | 
| 1082 | 	return NULL; | 
| 1083 | } | 
| 1084 |  | 
| 1085 | /* Create new edvice nodes in mapper/ dir. */ | 
| 1086 | void dm_task_update_nodes(void) | 
| 1087 | { | 
| 1088 | 	update_devs(); | 
| 1089 | } | 
| 1090 |  | 
| 1091 | /* Run dm command which is descirbed in dm_task structure. */ | 
| 1092 | int dm_task_run(struct dm_task *dmt) | 
| 1093 | { | 
| 1094 | 	struct dm_ioctl *dmi; | 
| 1095 | 	unsigned command; | 
| 1096 |  | 
| 1097 | 	if ((unsigned) dmt->type >= | 
| 1098 | 	    (sizeof(_cmd_data_v4) / sizeof(*_cmd_data_v4))) { | 
| 1099 | 		log_error("Internal error: unknown device-mapper task %d" , | 
| 1100 | 			  dmt->type); | 
| 1101 | 		return 0; | 
| 1102 | 	} | 
| 1103 |  | 
| 1104 | 	command = _cmd_data_v4[dmt->type].cmd; | 
| 1105 |  | 
| 1106 | 	/* Old-style creation had a table supplied */ | 
| 1107 | 	if (dmt->type == DM_DEVICE_CREATE && dmt->head) | 
| 1108 | 		return _create_and_load_v4(dmt); | 
| 1109 |  | 
| 1110 | 	if (dmt->type == DM_DEVICE_MKNODES && !dmt->dev_name && | 
| 1111 | 	    !dmt->uuid && dmt->major <= 0) | 
| 1112 | 		return _mknodes_v4(dmt); | 
| 1113 |  | 
| 1114 | 	if ((dmt->type == DM_DEVICE_RELOAD) && dmt->suppress_identical_reload) | 
| 1115 | 		return _reload_with_suppression_v4(dmt); | 
| 1116 |  | 
| 1117 | 	if (!_open_control()) | 
| 1118 | 		return 0; | 
| 1119 |  | 
| 1120 | 	if (!(dmi = _do_dm_ioctl(dmt, command))) | 
| 1121 | 		return 0; | 
| 1122 |  | 
| 1123 | 	switch (dmt->type) { | 
| 1124 | 	case DM_DEVICE_CREATE: | 
| 1125 | 		add_dev_node(dmt->dev_name, MAJOR(dmi->dev), MINOR(dmi->dev), | 
| 1126 | 		    dmt->uid, dmt->gid, dmt->mode, 0); | 
| 1127 | 		break; | 
| 1128 |  | 
| 1129 | 	case DM_DEVICE_REMOVE: | 
| 1130 | 		/* FIXME Kernel needs to fill in dmi->name */ | 
| 1131 | 		if (dmt->dev_name) | 
| 1132 | 			rm_dev_node(dmt->dev_name, 0); | 
| 1133 | 		break; | 
| 1134 |  | 
| 1135 | 	case DM_DEVICE_RENAME: | 
| 1136 | 		/* FIXME Kernel needs to fill in dmi->name */ | 
| 1137 | 		if (dmt->dev_name) | 
| 1138 | 			rename_dev_node(dmt->dev_name, dmt->newname, 0); | 
| 1139 | 		break; | 
| 1140 |  | 
| 1141 | 	case DM_DEVICE_RESUME: | 
| 1142 | 		/* FIXME Kernel needs to fill in dmi->name */ | 
| 1143 | 		set_dev_node_read_ahead(dmt->dev_name, dmt->read_ahead, | 
| 1144 | 					dmt->read_ahead_flags); | 
| 1145 | 		break; | 
| 1146 |  | 
| 1147 | 	case DM_DEVICE_MKNODES: | 
| 1148 | 		if (dmi->flags & DM_EXISTS_FLAG) | 
| 1149 | 			add_dev_node(dmi->name, MAJOR(dmi->dev), | 
| 1150 | 				     MINOR(dmi->dev), | 
| 1151 | 			    dmt->uid, dmt->gid, dmt->mode, 0); | 
| 1152 | 		else if (dmt->dev_name) | 
| 1153 | 			rm_dev_node(dmt->dev_name, 0); | 
| 1154 | 		break; | 
| 1155 |  | 
| 1156 | 	case DM_DEVICE_STATUS: | 
| 1157 | 	case DM_DEVICE_TABLE: | 
| 1158 | 	case DM_DEVICE_WAITEVENT: | 
| 1159 | 		if (!_unmarshal_status(dmt, dmi)) | 
| 1160 | 			goto bad; | 
| 1161 | 		break; | 
| 1162 | 	} | 
| 1163 |  | 
| 1164 | 	/* Was structure reused? */ | 
| 1165 | 	if (dmt->dmi.v4) | 
| 1166 | 		dm_free(dmt->dmi.v4); | 
| 1167 |  | 
| 1168 | 	dmt->dmi.v4 = dmi; | 
| 1169 | 	return 1; | 
| 1170 |  | 
| 1171 |       bad: | 
| 1172 | 	dm_free(dmi); | 
| 1173 | 	return 0; | 
| 1174 | } | 
| 1175 |  | 
| 1176 | void dm_lib_release(void) | 
| 1177 | { | 
| 1178 | 	if (_control_fd != -1) { | 
| 1179 | 		close(_control_fd); | 
| 1180 | 		_control_fd = -1; | 
| 1181 | 	} | 
| 1182 | 	update_devs(); | 
| 1183 | } | 
| 1184 |  | 
| 1185 | void dm_lib_exit(void) | 
| 1186 | { | 
| 1187 | 	dm_lib_release(); | 
| 1188 | 	dm_dump_memory(); | 
| 1189 | 	_version_ok = 1; | 
| 1190 | 	_version_checked = 0; | 
| 1191 | } | 
| 1192 |  |